pdf.js ➔ ... ➔ putBinaryImageData   F
last analyzed

Complexity

Conditions 32
Paths > 20000

Size

Total Lines 120

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 120
rs 2
cc 32
nc 2359348
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like pdf.js ➔ ... ➔ putBinaryImageData often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
3
/* Copyright 2012 Mozilla Foundation
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
/*jshint globalstrict: false */
18
/* globals PDFJS */
19
20
// Initializing PDFJS global object (if still undefined)
21
if (typeof PDFJS === 'undefined') {
22
  (typeof window !== 'undefined' ? window : this).PDFJS = {};
23
}
24
25
PDFJS.version = '1.1.114';
26
PDFJS.build = '3fd44fd';
27
28
(function pdfjsWrapper() {
29
  // Use strict in our context only - users might not want it
30
  'use strict';
31
32
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
33
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
34
/* Copyright 2012 Mozilla Foundation
35
 *
36
 * Licensed under the Apache License, Version 2.0 (the "License");
37
 * you may not use this file except in compliance with the License.
38
 * You may obtain a copy of the License at
39
 *
40
 *     http://www.apache.org/licenses/LICENSE-2.0
41
 *
42
 * Unless required by applicable law or agreed to in writing, software
43
 * distributed under the License is distributed on an "AS IS" BASIS,
44
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45
 * See the License for the specific language governing permissions and
46
 * limitations under the License.
47
 */
48
/* globals Cmd, ColorSpace, Dict, MozBlobBuilder, Name, PDFJS, Ref, URL,
49
           Promise */
50
51
'use strict';
52
53
var globalScope = (typeof window === 'undefined') ? this : window;
54
55
var isWorker = (typeof window === 'undefined');
56
57
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
58
59
var TextRenderingMode = {
60
  FILL: 0,
61
  STROKE: 1,
62
  FILL_STROKE: 2,
63
  INVISIBLE: 3,
64
  FILL_ADD_TO_PATH: 4,
65
  STROKE_ADD_TO_PATH: 5,
66
  FILL_STROKE_ADD_TO_PATH: 6,
67
  ADD_TO_PATH: 7,
68
  FILL_STROKE_MASK: 3,
69
  ADD_TO_PATH_FLAG: 4
70
};
71
72
var ImageKind = {
73
  GRAYSCALE_1BPP: 1,
74
  RGB_24BPP: 2,
75
  RGBA_32BPP: 3
76
};
77
78
var AnnotationType = {
0 ignored issues
show
Unused Code introduced by
The variable AnnotationType seems to be never used. Consider removing it.
Loading history...
79
  WIDGET: 1,
80
  TEXT: 2,
81
  LINK: 3
82
};
83
84
var StreamType = {
0 ignored issues
show
Unused Code introduced by
The variable StreamType seems to be never used. Consider removing it.
Loading history...
85
  UNKNOWN: 0,
86
  FLATE: 1,
87
  LZW: 2,
88
  DCT: 3,
89
  JPX: 4,
90
  JBIG: 5,
91
  A85: 6,
92
  AHX: 7,
93
  CCF: 8,
94
  RL: 9
95
};
96
97
var FontType = {
0 ignored issues
show
Unused Code introduced by
The variable FontType seems to be never used. Consider removing it.
Loading history...
98
  UNKNOWN: 0,
99
  TYPE1: 1,
100
  TYPE1C: 2,
101
  CIDFONTTYPE0: 3,
102
  CIDFONTTYPE0C: 4,
103
  TRUETYPE: 5,
104
  CIDFONTTYPE2: 6,
105
  TYPE3: 7,
106
  OPENTYPE: 8,
107
  TYPE0: 9,
108
  MMTYPE1: 10
109
};
110
111
// The global PDFJS object exposes the API
112
// In production, it will be declared outside a global wrapper
113
// In development, it will be declared here
114
if (!globalScope.PDFJS) {
115
  globalScope.PDFJS = {};
116
}
117
118
globalScope.PDFJS.pdfBug = false;
119
120
PDFJS.VERBOSITY_LEVELS = {
121
  errors: 0,
122
  warnings: 1,
123
  infos: 5
124
};
125
126
// All the possible operations for an operator list.
127
var OPS = PDFJS.OPS = {
128
  // Intentionally start from 1 so it is easy to spot bad operators that will be
129
  // 0's.
130
  dependency: 1,
131
  setLineWidth: 2,
132
  setLineCap: 3,
133
  setLineJoin: 4,
134
  setMiterLimit: 5,
135
  setDash: 6,
136
  setRenderingIntent: 7,
137
  setFlatness: 8,
138
  setGState: 9,
139
  save: 10,
140
  restore: 11,
141
  transform: 12,
142
  moveTo: 13,
143
  lineTo: 14,
144
  curveTo: 15,
145
  curveTo2: 16,
146
  curveTo3: 17,
147
  closePath: 18,
148
  rectangle: 19,
149
  stroke: 20,
150
  closeStroke: 21,
151
  fill: 22,
152
  eoFill: 23,
153
  fillStroke: 24,
154
  eoFillStroke: 25,
155
  closeFillStroke: 26,
156
  closeEOFillStroke: 27,
157
  endPath: 28,
158
  clip: 29,
159
  eoClip: 30,
160
  beginText: 31,
161
  endText: 32,
162
  setCharSpacing: 33,
163
  setWordSpacing: 34,
164
  setHScale: 35,
165
  setLeading: 36,
166
  setFont: 37,
167
  setTextRenderingMode: 38,
168
  setTextRise: 39,
169
  moveText: 40,
170
  setLeadingMoveText: 41,
171
  setTextMatrix: 42,
172
  nextLine: 43,
173
  showText: 44,
174
  showSpacedText: 45,
175
  nextLineShowText: 46,
176
  nextLineSetSpacingShowText: 47,
177
  setCharWidth: 48,
178
  setCharWidthAndBounds: 49,
179
  setStrokeColorSpace: 50,
180
  setFillColorSpace: 51,
181
  setStrokeColor: 52,
182
  setStrokeColorN: 53,
183
  setFillColor: 54,
184
  setFillColorN: 55,
185
  setStrokeGray: 56,
186
  setFillGray: 57,
187
  setStrokeRGBColor: 58,
188
  setFillRGBColor: 59,
189
  setStrokeCMYKColor: 60,
190
  setFillCMYKColor: 61,
191
  shadingFill: 62,
192
  beginInlineImage: 63,
193
  beginImageData: 64,
194
  endInlineImage: 65,
195
  paintXObject: 66,
196
  markPoint: 67,
197
  markPointProps: 68,
198
  beginMarkedContent: 69,
199
  beginMarkedContentProps: 70,
200
  endMarkedContent: 71,
201
  beginCompat: 72,
202
  endCompat: 73,
203
  paintFormXObjectBegin: 74,
204
  paintFormXObjectEnd: 75,
205
  beginGroup: 76,
206
  endGroup: 77,
207
  beginAnnotations: 78,
208
  endAnnotations: 79,
209
  beginAnnotation: 80,
210
  endAnnotation: 81,
211
  paintJpegXObject: 82,
212
  paintImageMaskXObject: 83,
213
  paintImageMaskXObjectGroup: 84,
214
  paintImageXObject: 85,
215
  paintInlineImageXObject: 86,
216
  paintInlineImageXObjectGroup: 87,
217
  paintImageXObjectRepeat: 88,
218
  paintImageMaskXObjectRepeat: 89,
219
  paintSolidColorImageMask: 90,
220
  constructPath: 91
221
};
222
223
// A notice for devs. These are good for things that are helpful to devs, such
224
// as warning that Workers were disabled, which is important to devs but not
225
// end users.
226
function info(msg) {
227
  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
228
    console.log('Info: ' + msg);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
229
  }
230
}
231
232
// Non-fatal warnings.
233
function warn(msg) {
234
  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
235
    console.log('Warning: ' + msg);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
236
  }
237
}
238
239
// Fatal errors that should trigger the fallback UI and halt execution by
240
// throwing an exception.
241
function error(msg) {
242
  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) {
243
    console.log('Error: ' + msg);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
244
    console.log(backtrace());
245
  }
246
  UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
247
  throw new Error(msg);
248
}
249
250
function backtrace() {
251
  try {
252
    throw new Error();
253
  } catch (e) {
254
    return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
255
  }
256
}
257
258
function assert(cond, msg) {
259
  if (!cond) {
260
    error(msg);
261
  }
262
}
263
264
var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
265
  unknown: 'unknown',
266
  forms: 'forms',
267
  javaScript: 'javaScript',
268
  smask: 'smask',
269
  shadingPattern: 'shadingPattern',
270
  font: 'font'
271
};
272
273
var UnsupportedManager = PDFJS.UnsupportedManager =
274
  (function UnsupportedManagerClosure() {
275
  var listeners = [];
276
  return {
277
    listen: function (cb) {
278
      listeners.push(cb);
279
    },
280
    notify: function (featureId) {
281
      warn('Unsupported feature "' + featureId + '"');
282
      for (var i = 0, ii = listeners.length; i < ii; i++) {
283
        listeners[i](featureId);
284
      }
285
    }
286
  };
287
})();
288
289
// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
290
// absolute URL, it will be returned as is.
291
function combineUrl(baseUrl, url) {
292
  if (!url) {
293
    return baseUrl;
294
  }
295
  if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
296
    return url;
297
  }
298
  var i;
299
  if (url.charAt(0) === '/') {
300
    // absolute path
301
    i = baseUrl.indexOf('://');
302
    if (url.charAt(1) === '/') {
303
      ++i;
304
    } else {
305
      i = baseUrl.indexOf('/', i + 3);
306
    }
307
    return baseUrl.substring(0, i) + url;
308
  } else {
309
    // relative path
310
    var pathLength = baseUrl.length;
311
    i = baseUrl.lastIndexOf('#');
312
    pathLength = i >= 0 ? i : pathLength;
313
    i = baseUrl.lastIndexOf('?', pathLength);
314
    pathLength = i >= 0 ? i : pathLength;
315
    var prefixLength = baseUrl.lastIndexOf('/', pathLength);
316
    return baseUrl.substring(0, prefixLength + 1) + url;
317
  }
318
}
319
320
// Validates if URL is safe and allowed, e.g. to avoid XSS.
321
function isValidUrl(url, allowRelative) {
322
  if (!url) {
323
    return false;
324
  }
325
  // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
326
  // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
327
  var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url);
328
  if (!protocol) {
329
    return allowRelative;
330
  }
331
  protocol = protocol[0].toLowerCase();
332
  switch (protocol) {
333
    case 'http':
334
    case 'https':
335
    case 'ftp':
336
    case 'mailto':
337
    case 'tel':
338
      return true;
339
    default:
340
      return false;
341
  }
342
}
343
PDFJS.isValidUrl = isValidUrl;
344
345
function shadow(obj, prop, value) {
346
  Object.defineProperty(obj, prop, { value: value,
347
                                     enumerable: true,
348
                                     configurable: true,
349
                                     writable: false });
350
  return value;
351
}
352
PDFJS.shadow = shadow;
353
354
var PasswordResponses = PDFJS.PasswordResponses = {
355
  NEED_PASSWORD: 1,
356
  INCORRECT_PASSWORD: 2
357
};
358
359
var PasswordException = (function PasswordExceptionClosure() {
360
  function PasswordException(msg, code) {
361
    this.name = 'PasswordException';
362
    this.message = msg;
363
    this.code = code;
364
  }
365
366
  PasswordException.prototype = new Error();
367
  PasswordException.constructor = PasswordException;
368
369
  return PasswordException;
370
})();
371
PDFJS.PasswordException = PasswordException;
372
373
var UnknownErrorException = (function UnknownErrorExceptionClosure() {
374
  function UnknownErrorException(msg, details) {
375
    this.name = 'UnknownErrorException';
376
    this.message = msg;
377
    this.details = details;
378
  }
379
380
  UnknownErrorException.prototype = new Error();
381
  UnknownErrorException.constructor = UnknownErrorException;
382
383
  return UnknownErrorException;
384
})();
385
PDFJS.UnknownErrorException = UnknownErrorException;
386
387
var InvalidPDFException = (function InvalidPDFExceptionClosure() {
388
  function InvalidPDFException(msg) {
389
    this.name = 'InvalidPDFException';
390
    this.message = msg;
391
  }
392
393
  InvalidPDFException.prototype = new Error();
394
  InvalidPDFException.constructor = InvalidPDFException;
395
396
  return InvalidPDFException;
397
})();
398
PDFJS.InvalidPDFException = InvalidPDFException;
399
400
var MissingPDFException = (function MissingPDFExceptionClosure() {
401
  function MissingPDFException(msg) {
402
    this.name = 'MissingPDFException';
403
    this.message = msg;
404
  }
405
406
  MissingPDFException.prototype = new Error();
407
  MissingPDFException.constructor = MissingPDFException;
408
409
  return MissingPDFException;
410
})();
411
PDFJS.MissingPDFException = MissingPDFException;
412
413
var UnexpectedResponseException =
414
    (function UnexpectedResponseExceptionClosure() {
415
  function UnexpectedResponseException(msg, status) {
416
    this.name = 'UnexpectedResponseException';
417
    this.message = msg;
418
    this.status = status;
419
  }
420
421
  UnexpectedResponseException.prototype = new Error();
422
  UnexpectedResponseException.constructor = UnexpectedResponseException;
423
424
  return UnexpectedResponseException;
425
})();
426
PDFJS.UnexpectedResponseException = UnexpectedResponseException;
427
428
var NotImplementedException = (function NotImplementedExceptionClosure() {
0 ignored issues
show
Unused Code introduced by
The variable NotImplementedException seems to be never used. Consider removing it.
Loading history...
429
  function NotImplementedException(msg) {
430
    this.message = msg;
431
  }
432
433
  NotImplementedException.prototype = new Error();
434
  NotImplementedException.prototype.name = 'NotImplementedException';
435
  NotImplementedException.constructor = NotImplementedException;
436
437
  return NotImplementedException;
438
})();
439
440
var MissingDataException = (function MissingDataExceptionClosure() {
0 ignored issues
show
Unused Code introduced by
The variable MissingDataException seems to be never used. Consider removing it.
Loading history...
441
  function MissingDataException(begin, end) {
442
    this.begin = begin;
443
    this.end = end;
444
    this.message = 'Missing data [' + begin + ', ' + end + ')';
445
  }
446
447
  MissingDataException.prototype = new Error();
448
  MissingDataException.prototype.name = 'MissingDataException';
449
  MissingDataException.constructor = MissingDataException;
450
451
  return MissingDataException;
452
})();
453
454
var XRefParseException = (function XRefParseExceptionClosure() {
0 ignored issues
show
Unused Code introduced by
The variable XRefParseException seems to be never used. Consider removing it.
Loading history...
455
  function XRefParseException(msg) {
456
    this.message = msg;
457
  }
458
459
  XRefParseException.prototype = new Error();
460
  XRefParseException.prototype.name = 'XRefParseException';
461
  XRefParseException.constructor = XRefParseException;
462
463
  return XRefParseException;
464
})();
465
466
467
function bytesToString(bytes) {
468
  assert(bytes !== null && typeof bytes === 'object' &&
469
         bytes.length !== undefined, 'Invalid argument for bytesToString');
470
  var length = bytes.length;
471
  var MAX_ARGUMENT_COUNT = 8192;
472
  if (length < MAX_ARGUMENT_COUNT) {
473
    return String.fromCharCode.apply(null, bytes);
474
  }
475
  var strBuf = [];
476
  for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
477
    var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
478
    var chunk = bytes.subarray(i, chunkEnd);
479
    strBuf.push(String.fromCharCode.apply(null, chunk));
480
  }
481
  return strBuf.join('');
482
}
483
484
function stringToBytes(str) {
485
  assert(typeof str === 'string', 'Invalid argument for stringToBytes');
486
  var length = str.length;
487
  var bytes = new Uint8Array(length);
488
  for (var i = 0; i < length; ++i) {
489
    bytes[i] = str.charCodeAt(i) & 0xFF;
490
  }
491
  return bytes;
492
}
493
494
function string32(value) {
495
  return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
496
                             (value >> 8) & 0xff, value & 0xff);
497
}
498
499
function log2(x) {
0 ignored issues
show
introduced by
The function log2 does not seem to be used and can be removed.
Loading history...
500
  var n = 1, i = 0;
501
  while (x > n) {
502
    n <<= 1;
503
    i++;
504
  }
505
  return i;
506
}
507
508
function readInt8(data, start) {
0 ignored issues
show
introduced by
The function readInt8 does not seem to be used and can be removed.
Loading history...
509
  return (data[start] << 24) >> 24;
510
}
511
512
function readUint16(data, offset) {
0 ignored issues
show
introduced by
The function readUint16 does not seem to be used and can be removed.
Loading history...
513
  return (data[offset] << 8) | data[offset + 1];
514
}
515
516
function readUint32(data, offset) {
0 ignored issues
show
introduced by
The function readUint32 does not seem to be used and can be removed.
Loading history...
517
  return ((data[offset] << 24) | (data[offset + 1] << 16) |
518
         (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
519
}
520
521
// Lazy test the endianness of the platform
522
// NOTE: This will be 'true' for simulated TypedArrays
523
function isLittleEndian() {
524
  var buffer8 = new Uint8Array(2);
525
  buffer8[0] = 1;
526
  var buffer16 = new Uint16Array(buffer8.buffer);
527
  return (buffer16[0] === 1);
528
}
529
530
Object.defineProperty(PDFJS, 'isLittleEndian', {
531
  configurable: true,
532
  get: function PDFJS_isLittleEndian() {
533
    return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
534
  }
535
});
536
537
//#if !(FIREFOX || MOZCENTRAL || B2G || CHROME)
538
//// Lazy test if the userAgant support CanvasTypedArrays
539
function hasCanvasTypedArrays() {
540
  var canvas = document.createElement('canvas');
541
  canvas.width = canvas.height = 1;
542
  var ctx = canvas.getContext('2d');
543
  var imageData = ctx.createImageData(1, 1);
544
  return (typeof imageData.data.buffer !== 'undefined');
545
}
546
547
Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
548
  configurable: true,
549
  get: function PDFJS_hasCanvasTypedArrays() {
550
    return shadow(PDFJS, 'hasCanvasTypedArrays', hasCanvasTypedArrays());
551
  }
552
});
553
554
var Uint32ArrayView = (function Uint32ArrayViewClosure() {
555
556
  function Uint32ArrayView(buffer, length) {
557
    this.buffer = buffer;
558
    this.byteLength = buffer.length;
559
    this.length = length === undefined ? (this.byteLength >> 2) : length;
560
    ensureUint32ArrayViewProps(this.length);
561
  }
562
  Uint32ArrayView.prototype = Object.create(null);
563
564
  var uint32ArrayViewSetters = 0;
565
  function createUint32ArrayProp(index) {
566
    return {
567
      get: function () {
568
        var buffer = this.buffer, offset = index << 2;
569
        return (buffer[offset] | (buffer[offset + 1] << 8) |
570
          (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
571
      },
572
      set: function (value) {
573
        var buffer = this.buffer, offset = index << 2;
574
        buffer[offset] = value & 255;
575
        buffer[offset + 1] = (value >> 8) & 255;
576
        buffer[offset + 2] = (value >> 16) & 255;
577
        buffer[offset + 3] = (value >>> 24) & 255;
578
      }
579
    };
580
  }
581
582
  function ensureUint32ArrayViewProps(length) {
583
    while (uint32ArrayViewSetters < length) {
0 ignored issues
show
Bug introduced by
The variable uint32ArrayViewSetters is changed as part of the while loop for example by uint32ArrayViewSetters++ on line 587. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
584
      Object.defineProperty(Uint32ArrayView.prototype,
585
        uint32ArrayViewSetters,
586
        createUint32ArrayProp(uint32ArrayViewSetters));
587
      uint32ArrayViewSetters++;
588
    }
589
  }
590
591
  return Uint32ArrayView;
592
})();
593
//#else
594
//PDFJS.hasCanvasTypedArrays = true;
595
//#endif
596
597
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
598
599
var Util = PDFJS.Util = (function UtilClosure() {
600
  function Util() {}
601
602
  var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
603
604
  // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
605
  // creating many intermediate strings.
606
  Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
607
    rgbBuf[1] = r;
608
    rgbBuf[3] = g;
609
    rgbBuf[5] = b;
610
    return rgbBuf.join('');
611
  };
612
613
  // Concatenates two transformation matrices together and returns the result.
614
  Util.transform = function Util_transform(m1, m2) {
615
    return [
616
      m1[0] * m2[0] + m1[2] * m2[1],
617
      m1[1] * m2[0] + m1[3] * m2[1],
618
      m1[0] * m2[2] + m1[2] * m2[3],
619
      m1[1] * m2[2] + m1[3] * m2[3],
620
      m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
621
      m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
622
    ];
623
  };
624
625
  // For 2d affine transforms
626
  Util.applyTransform = function Util_applyTransform(p, m) {
627
    var xt = p[0] * m[0] + p[1] * m[2] + m[4];
628
    var yt = p[0] * m[1] + p[1] * m[3] + m[5];
629
    return [xt, yt];
630
  };
631
632
  Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
633
    var d = m[0] * m[3] - m[1] * m[2];
634
    var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
635
    var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
636
    return [xt, yt];
637
  };
638
639
  // Applies the transform to the rectangle and finds the minimum axially
640
  // aligned bounding box.
641
  Util.getAxialAlignedBoundingBox =
642
    function Util_getAxialAlignedBoundingBox(r, m) {
643
644
    var p1 = Util.applyTransform(r, m);
645
    var p2 = Util.applyTransform(r.slice(2, 4), m);
646
    var p3 = Util.applyTransform([r[0], r[3]], m);
647
    var p4 = Util.applyTransform([r[2], r[1]], m);
648
    return [
649
      Math.min(p1[0], p2[0], p3[0], p4[0]),
650
      Math.min(p1[1], p2[1], p3[1], p4[1]),
651
      Math.max(p1[0], p2[0], p3[0], p4[0]),
652
      Math.max(p1[1], p2[1], p3[1], p4[1])
653
    ];
654
  };
655
656
  Util.inverseTransform = function Util_inverseTransform(m) {
657
    var d = m[0] * m[3] - m[1] * m[2];
658
    return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
659
      (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
660
  };
661
662
  // Apply a generic 3d matrix M on a 3-vector v:
663
  //   | a b c |   | X |
664
  //   | d e f | x | Y |
665
  //   | g h i |   | Z |
666
  // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
667
  // with v as [X,Y,Z]
668
  Util.apply3dTransform = function Util_apply3dTransform(m, v) {
669
    return [
670
      m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
671
      m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
672
      m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
673
    ];
674
  };
675
676
  // This calculation uses Singular Value Decomposition.
677
  // The SVD can be represented with formula A = USV. We are interested in the
678
  // matrix S here because it represents the scale values.
679
  Util.singularValueDecompose2dScale =
680
    function Util_singularValueDecompose2dScale(m) {
681
682
    var transpose = [m[0], m[2], m[1], m[3]];
683
684
    // Multiply matrix m with its transpose.
685
    var a = m[0] * transpose[0] + m[1] * transpose[2];
686
    var b = m[0] * transpose[1] + m[1] * transpose[3];
687
    var c = m[2] * transpose[0] + m[3] * transpose[2];
688
    var d = m[2] * transpose[1] + m[3] * transpose[3];
689
690
    // Solve the second degree polynomial to get roots.
691
    var first = (a + d) / 2;
692
    var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
693
    var sx = first + second || 1;
694
    var sy = first - second || 1;
695
696
    // Scale values are the square roots of the eigenvalues.
697
    return [Math.sqrt(sx), Math.sqrt(sy)];
698
  };
699
700
  // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
701
  // For coordinate systems whose origin lies in the bottom-left, this
702
  // means normalization to (BL,TR) ordering. For systems with origin in the
703
  // top-left, this means (TL,BR) ordering.
704
  Util.normalizeRect = function Util_normalizeRect(rect) {
705
    var r = rect.slice(0); // clone rect
706
    if (rect[0] > rect[2]) {
707
      r[0] = rect[2];
708
      r[2] = rect[0];
709
    }
710
    if (rect[1] > rect[3]) {
711
      r[1] = rect[3];
712
      r[3] = rect[1];
713
    }
714
    return r;
715
  };
716
717
  // Returns a rectangle [x1, y1, x2, y2] corresponding to the
718
  // intersection of rect1 and rect2. If no intersection, returns 'false'
719
  // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
720
  Util.intersect = function Util_intersect(rect1, rect2) {
721
    function compare(a, b) {
722
      return a - b;
723
    }
724
725
    // Order points along the axes
726
    var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
727
        orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
728
        result = [];
729
730
    rect1 = Util.normalizeRect(rect1);
731
    rect2 = Util.normalizeRect(rect2);
732
733
    // X: first and second points belong to different rectangles?
734
    if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
735
        (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
736
      // Intersection must be between second and third points
737
      result[0] = orderedX[1];
738
      result[2] = orderedX[2];
739
    } else {
740
      return false;
741
    }
742
743
    // Y: first and second points belong to different rectangles?
744
    if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
745
        (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
746
      // Intersection must be between second and third points
747
      result[1] = orderedY[1];
748
      result[3] = orderedY[2];
749
    } else {
750
      return false;
751
    }
752
753
    return result;
754
  };
755
756
  Util.sign = function Util_sign(num) {
757
    return num < 0 ? -1 : 1;
758
  };
759
760
  Util.appendToArray = function Util_appendToArray(arr1, arr2) {
761
    Array.prototype.push.apply(arr1, arr2);
762
  };
763
764
  Util.prependToArray = function Util_prependToArray(arr1, arr2) {
765
    Array.prototype.unshift.apply(arr1, arr2);
766
  };
767
768
  Util.extendObj = function extendObj(obj1, obj2) {
769
    for (var key in obj2) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
770
      obj1[key] = obj2[key];
771
    }
772
  };
773
774
  Util.getInheritableProperty = function Util_getInheritableProperty(dict,
775
                                                                     name) {
776
    while (dict && !dict.has(name)) {
777
      dict = dict.get('Parent');
778
    }
779
    if (!dict) {
780
      return null;
781
    }
782
    return dict.get(name);
783
  };
784
785
  Util.inherit = function Util_inherit(sub, base, prototype) {
786
    sub.prototype = Object.create(base.prototype);
787
    sub.prototype.constructor = sub;
788
    for (var prop in prototype) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
789
      sub.prototype[prop] = prototype[prop];
790
    }
791
  };
792
793
  Util.loadScript = function Util_loadScript(src, callback) {
794
    var script = document.createElement('script');
795
    var loaded = false;
796
    script.setAttribute('src', src);
797
    if (callback) {
798
      script.onload = function() {
799
        if (!loaded) {
800
          callback();
801
        }
802
        loaded = true;
803
      };
804
    }
805
    document.getElementsByTagName('head')[0].appendChild(script);
806
  };
807
808
  return Util;
809
})();
810
811
/**
812
 * PDF page viewport created based on scale, rotation and offset.
813
 * @class
814
 * @alias PDFJS.PageViewport
815
 */
816
var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
817
  /**
818
   * @constructor
819
   * @private
820
   * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
821
   * @param scale {number} scale of the viewport.
822
   * @param rotation {number} rotations of the viewport in degrees.
823
   * @param offsetX {number} offset X
824
   * @param offsetY {number} offset Y
825
   * @param dontFlip {boolean} if true, axis Y will not be flipped.
826
   */
827
  function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
828
    this.viewBox = viewBox;
829
    this.scale = scale;
830
    this.rotation = rotation;
831
    this.offsetX = offsetX;
832
    this.offsetY = offsetY;
833
834
    // creating transform to convert pdf coordinate system to the normal
835
    // canvas like coordinates taking in account scale and rotation
836
    var centerX = (viewBox[2] + viewBox[0]) / 2;
837
    var centerY = (viewBox[3] + viewBox[1]) / 2;
838
    var rotateA, rotateB, rotateC, rotateD;
839
    rotation = rotation % 360;
840
    rotation = rotation < 0 ? rotation + 360 : rotation;
841
    switch (rotation) {
842
      case 180:
843
        rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
844
        break;
845
      case 90:
846
        rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
847
        break;
848
      case 270:
849
        rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
850
        break;
851
      //case 0:
852
      default:
853
        rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
854
        break;
855
    }
856
857
    if (dontFlip) {
858
      rotateC = -rotateC; rotateD = -rotateD;
859
    }
860
861
    var offsetCanvasX, offsetCanvasY;
862
    var width, height;
863
    if (rotateA === 0) {
864
      offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
865
      offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
866
      width = Math.abs(viewBox[3] - viewBox[1]) * scale;
867
      height = Math.abs(viewBox[2] - viewBox[0]) * scale;
868
    } else {
869
      offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
870
      offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
871
      width = Math.abs(viewBox[2] - viewBox[0]) * scale;
872
      height = Math.abs(viewBox[3] - viewBox[1]) * scale;
873
    }
874
    // creating transform for the following operations:
875
    // translate(-centerX, -centerY), rotate and flip vertically,
876
    // scale, and translate(offsetCanvasX, offsetCanvasY)
877
    this.transform = [
878
      rotateA * scale,
879
      rotateB * scale,
880
      rotateC * scale,
881
      rotateD * scale,
882
      offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
883
      offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
884
    ];
885
886
    this.width = width;
887
    this.height = height;
888
    this.fontScale = scale;
889
  }
890
  PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
891
    /**
892
     * Clones viewport with additional properties.
893
     * @param args {Object} (optional) If specified, may contain the 'scale' or
894
     * 'rotation' properties to override the corresponding properties in
895
     * the cloned viewport.
896
     * @returns {PDFJS.PageViewport} Cloned viewport.
897
     */
898
    clone: function PageViewPort_clone(args) {
899
      args = args || {};
900
      var scale = 'scale' in args ? args.scale : this.scale;
901
      var rotation = 'rotation' in args ? args.rotation : this.rotation;
902
      return new PageViewport(this.viewBox.slice(), scale, rotation,
903
                              this.offsetX, this.offsetY, args.dontFlip);
904
    },
905
    /**
906
     * Converts PDF point to the viewport coordinates. For examples, useful for
907
     * converting PDF location into canvas pixel coordinates.
908
     * @param x {number} X coordinate.
909
     * @param y {number} Y coordinate.
910
     * @returns {Object} Object that contains 'x' and 'y' properties of the
911
     * point in the viewport coordinate space.
912
     * @see {@link convertToPdfPoint}
913
     * @see {@link convertToViewportRectangle}
914
     */
915
    convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
916
      return Util.applyTransform([x, y], this.transform);
917
    },
918
    /**
919
     * Converts PDF rectangle to the viewport coordinates.
920
     * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
921
     * @returns {Array} Contains corresponding coordinates of the rectangle
922
     * in the viewport coordinate space.
923
     * @see {@link convertToViewportPoint}
924
     */
925
    convertToViewportRectangle:
926
      function PageViewport_convertToViewportRectangle(rect) {
927
      var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
928
      var br = Util.applyTransform([rect[2], rect[3]], this.transform);
929
      return [tl[0], tl[1], br[0], br[1]];
930
    },
931
    /**
932
     * Converts viewport coordinates to the PDF location. For examples, useful
933
     * for converting canvas pixel location into PDF one.
934
     * @param x {number} X coordinate.
935
     * @param y {number} Y coordinate.
936
     * @returns {Object} Object that contains 'x' and 'y' properties of the
937
     * point in the PDF coordinate space.
938
     * @see {@link convertToViewportPoint}
939
     */
940
    convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
941
      return Util.applyInverseTransform([x, y], this.transform);
942
    }
943
  };
944
  return PageViewport;
945
})();
946
947
var PDFStringTranslateTable = [
948
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
949
  0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
950
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
951
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
952
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
953
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
954
  0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
955
  0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
956
  0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
957
];
958
959
function stringToPDFString(str) {
0 ignored issues
show
introduced by
The function stringToPDFString does not seem to be used and can be removed.
Loading history...
960
  var i, n = str.length, strBuf = [];
961
  if (str[0] === '\xFE' && str[1] === '\xFF') {
962
    // UTF16BE BOM
963
    for (i = 2; i < n; i += 2) {
964
      strBuf.push(String.fromCharCode(
965
        (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
966
    }
967
  } else {
968
    for (i = 0; i < n; ++i) {
969
      var code = PDFStringTranslateTable[str.charCodeAt(i)];
970
      strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
971
    }
972
  }
973
  return strBuf.join('');
974
}
975
976
function stringToUTF8String(str) {
0 ignored issues
show
introduced by
The function stringToUTF8String does not seem to be used and can be removed.
Loading history...
977
  return decodeURIComponent(escape(str));
978
}
979
980
function isEmptyObj(obj) {
0 ignored issues
show
introduced by
The function isEmptyObj does not seem to be used and can be removed.
Loading history...
981
  for (var key in obj) {
982
    return false;
983
  }
984
  return true;
985
}
986
987
function isBool(v) {
0 ignored issues
show
introduced by
The function isBool does not seem to be used and can be removed.
Loading history...
988
  return typeof v === 'boolean';
989
}
990
991
function isInt(v) {
0 ignored issues
show
introduced by
The function isInt does not seem to be used and can be removed.
Loading history...
992
  return typeof v === 'number' && ((v | 0) === v);
993
}
994
995
function isNum(v) {
996
  return typeof v === 'number';
997
}
998
999
function isString(v) {
0 ignored issues
show
introduced by
The function isString does not seem to be used and can be removed.
Loading history...
1000
  return typeof v === 'string';
1001
}
1002
1003
function isName(v) {
1004
  return v instanceof Name;
1005
}
1006
1007
function isCmd(v, cmd) {
0 ignored issues
show
introduced by
The function isCmd does not seem to be used and can be removed.
Loading history...
1008
  return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);
1009
}
1010
1011
function isDict(v, type) {
0 ignored issues
show
introduced by
The function isDict does not seem to be used and can be removed.
Loading history...
1012
  if (!(v instanceof Dict)) {
1013
    return false;
1014
  }
1015
  if (!type) {
1016
    return true;
1017
  }
1018
  var dictType = v.get('Type');
1019
  return isName(dictType) && dictType.name === type;
1020
}
1021
1022
function isArray(v) {
1023
  return v instanceof Array;
1024
}
1025
1026
function isStream(v) {
0 ignored issues
show
introduced by
The function isStream does not seem to be used and can be removed.
Loading history...
1027
  return typeof v === 'object' && v !== null && v.getBytes !== undefined;
1028
}
1029
1030
function isArrayBuffer(v) {
1031
  return typeof v === 'object' && v !== null && v.byteLength !== undefined;
1032
}
1033
1034
function isRef(v) {
0 ignored issues
show
introduced by
The function isRef does not seem to be used and can be removed.
Loading history...
1035
  return v instanceof Ref;
1036
}
1037
1038
/**
1039
 * Promise Capability object.
1040
 *
1041
 * @typedef {Object} PromiseCapability
1042
 * @property {Promise} promise - A promise object.
1043
 * @property {function} resolve - Fullfills the promise.
1044
 * @property {function} reject - Rejects the promise.
1045
 */
1046
1047
/**
1048
 * Creates a promise capability object.
1049
 * @alias PDFJS.createPromiseCapability
1050
 *
1051
 * @return {PromiseCapability} A capability object contains:
1052
 * - a Promise, resolve and reject methods.
1053
 */
1054
function createPromiseCapability() {
1055
  var capability = {};
1056
  capability.promise = new Promise(function (resolve, reject) {
1057
    capability.resolve = resolve;
1058
    capability.reject = reject;
1059
  });
1060
  return capability;
1061
}
1062
1063
PDFJS.createPromiseCapability = createPromiseCapability;
1064
1065
/**
1066
 * Polyfill for Promises:
1067
 * The following promise implementation tries to generally implement the
1068
 * Promise/A+ spec. Some notable differences from other promise libaries are:
1069
 * - There currently isn't a seperate deferred and promise object.
1070
 * - Unhandled rejections eventually show an error if they aren't handled.
1071
 *
1072
 * Based off of the work in:
1073
 * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
1074
 */
1075
(function PromiseClosure() {
1076
  if (globalScope.Promise) {
1077
    // Promises existing in the DOM/Worker, checking presence of all/resolve
1078
    if (typeof globalScope.Promise.all !== 'function') {
1079
      globalScope.Promise.all = function (iterable) {
1080
        var count = 0, results = [], resolve, reject;
1081
        var promise = new globalScope.Promise(function (resolve_, reject_) {
1082
          resolve = resolve_;
1083
          reject = reject_;
1084
        });
1085
        iterable.forEach(function (p, i) {
1086
          count++;
1087
          p.then(function (result) {
1088
            results[i] = result;
1089
            count--;
1090
            if (count === 0) {
1091
              resolve(results);
1092
            }
1093
          }, reject);
1094
        });
1095
        if (count === 0) {
1096
          resolve(results);
1097
        }
1098
        return promise;
1099
      };
1100
    }
1101
    if (typeof globalScope.Promise.resolve !== 'function') {
1102
      globalScope.Promise.resolve = function (value) {
1103
        return new globalScope.Promise(function (resolve) { resolve(value); });
1104
      };
1105
    }
1106
    if (typeof globalScope.Promise.reject !== 'function') {
1107
      globalScope.Promise.reject = function (reason) {
1108
        return new globalScope.Promise(function (resolve, reject) {
1109
          reject(reason);
1110
        });
1111
      };
1112
    }
1113
    if (typeof globalScope.Promise.prototype.catch !== 'function') {
1114
      globalScope.Promise.prototype.catch = function (onReject) {
1115
        return globalScope.Promise.prototype.then(undefined, onReject);
1116
      };
1117
    }
1118
    return;
1119
  }
1120
//#if !MOZCENTRAL
1121
  var STATUS_PENDING = 0;
1122
  var STATUS_RESOLVED = 1;
1123
  var STATUS_REJECTED = 2;
1124
1125
  // In an attempt to avoid silent exceptions, unhandled rejections are
1126
  // tracked and if they aren't handled in a certain amount of time an
1127
  // error is logged.
1128
  var REJECTION_TIMEOUT = 500;
1129
1130
  var HandlerManager = {
1131
    handlers: [],
1132
    running: false,
1133
    unhandledRejections: [],
1134
    pendingRejectionCheck: false,
1135
1136
    scheduleHandlers: function scheduleHandlers(promise) {
1137
      if (promise._status === STATUS_PENDING) {
1138
        return;
1139
      }
1140
1141
      this.handlers = this.handlers.concat(promise._handlers);
1142
      promise._handlers = [];
1143
1144
      if (this.running) {
1145
        return;
1146
      }
1147
      this.running = true;
1148
1149
      setTimeout(this.runHandlers.bind(this), 0);
1150
    },
1151
1152
    runHandlers: function runHandlers() {
1153
      var RUN_TIMEOUT = 1; // ms
1154
      var timeoutAt = Date.now() + RUN_TIMEOUT;
1155
      while (this.handlers.length > 0) {
1156
        var handler = this.handlers.shift();
1157
1158
        var nextStatus = handler.thisPromise._status;
1159
        var nextValue = handler.thisPromise._value;
1160
1161
        try {
1162
          if (nextStatus === STATUS_RESOLVED) {
1163
            if (typeof handler.onResolve === 'function') {
1164
              nextValue = handler.onResolve(nextValue);
1165
            }
1166
          } else if (typeof handler.onReject === 'function') {
1167
              nextValue = handler.onReject(nextValue);
1168
              nextStatus = STATUS_RESOLVED;
1169
1170
              if (handler.thisPromise._unhandledRejection) {
1171
                this.removeUnhandeledRejection(handler.thisPromise);
1172
              }
1173
          }
1174
        } catch (ex) {
1175
          nextStatus = STATUS_REJECTED;
1176
          nextValue = ex;
1177
        }
1178
1179
        handler.nextPromise._updateStatus(nextStatus, nextValue);
1180
        if (Date.now() >= timeoutAt) {
1181
          break;
1182
        }
1183
      }
1184
1185
      if (this.handlers.length > 0) {
1186
        setTimeout(this.runHandlers.bind(this), 0);
1187
        return;
1188
      }
1189
1190
      this.running = false;
1191
    },
1192
1193
    addUnhandledRejection: function addUnhandledRejection(promise) {
1194
      this.unhandledRejections.push({
1195
        promise: promise,
1196
        time: Date.now()
1197
      });
1198
      this.scheduleRejectionCheck();
1199
    },
1200
1201
    removeUnhandeledRejection: function removeUnhandeledRejection(promise) {
1202
      promise._unhandledRejection = false;
1203
      for (var i = 0; i < this.unhandledRejections.length; i++) {
1204
        if (this.unhandledRejections[i].promise === promise) {
1205
          this.unhandledRejections.splice(i);
1206
          i--;
1207
        }
1208
      }
1209
    },
1210
1211
    scheduleRejectionCheck: function scheduleRejectionCheck() {
1212
      if (this.pendingRejectionCheck) {
1213
        return;
1214
      }
1215
      this.pendingRejectionCheck = true;
1216
      setTimeout(function rejectionCheck() {
1217
        this.pendingRejectionCheck = false;
1218
        var now = Date.now();
1219
        for (var i = 0; i < this.unhandledRejections.length; i++) {
1220
          if (now - this.unhandledRejections[i].time > REJECTION_TIMEOUT) {
1221
            var unhandled = this.unhandledRejections[i].promise._value;
1222
            var msg = 'Unhandled rejection: ' + unhandled;
1223
            if (unhandled.stack) {
1224
              msg += '\n' + unhandled.stack;
1225
            }
1226
            warn(msg);
1227
            this.unhandledRejections.splice(i);
1228
            i--;
1229
          }
1230
        }
1231
        if (this.unhandledRejections.length) {
1232
          this.scheduleRejectionCheck();
1233
        }
1234
      }.bind(this), REJECTION_TIMEOUT);
1235
    }
1236
  };
1237
1238
  function Promise(resolver) {
1239
    this._status = STATUS_PENDING;
1240
    this._handlers = [];
1241
    try {
1242
      resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
1243
    } catch (e) {
1244
      this._reject(e);
1245
    }
1246
  }
1247
  /**
1248
   * Builds a promise that is resolved when all the passed in promises are
1249
   * resolved.
1250
   * @param {array} array of data and/or promises to wait for.
0 ignored issues
show
Documentation introduced by
The parameter array does not exist. Did you maybe forget to remove this comment?
Loading history...
1251
   * @return {Promise} New dependant promise.
1252
   */
1253
  Promise.all = function Promise_all(promises) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Promise. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
1254
    var resolveAll, rejectAll;
1255
    var deferred = new Promise(function (resolve, reject) {
1256
      resolveAll = resolve;
1257
      rejectAll = reject;
1258
    });
1259
    var unresolved = promises.length;
1260
    var results = [];
1261
    if (unresolved === 0) {
1262
      resolveAll(results);
1263
      return deferred;
1264
    }
1265
    function reject(reason) {
1266
      if (deferred._status === STATUS_REJECTED) {
1267
        return;
1268
      }
1269
      results = [];
1270
      rejectAll(reason);
1271
    }
1272
    for (var i = 0, ii = promises.length; i < ii; ++i) {
1273
      var promise = promises[i];
1274
      var resolve = (function(i) {
1275
        return function(value) {
1276
          if (deferred._status === STATUS_REJECTED) {
1277
            return;
1278
          }
1279
          results[i] = value;
1280
          unresolved--;
1281
          if (unresolved === 0) {
0 ignored issues
show
Bug introduced by
The variable unresolved is changed as part of the for loop for example by unresolved-- on line 1280. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
1282
            resolveAll(results);
1283
          }
1284
        };
1285
      })(i);
1286
      if (Promise.isPromise(promise)) {
1287
        promise.then(resolve, reject);
1288
      } else {
1289
        resolve(promise);
1290
      }
1291
    }
1292
    return deferred;
1293
  };
1294
1295
  /**
1296
   * Checks if the value is likely a promise (has a 'then' function).
1297
   * @return {boolean} true if value is thenable
1298
   */
1299
  Promise.isPromise = function Promise_isPromise(value) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Promise. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
1300
    return value && typeof value.then === 'function';
1301
  };
1302
1303
  /**
1304
   * Creates resolved promise
1305
   * @param value resolve value
1306
   * @returns {Promise}
1307
   */
1308
  Promise.resolve = function Promise_resolve(value) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Promise. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
1309
    return new Promise(function (resolve) { resolve(value); });
1310
  };
1311
1312
  /**
1313
   * Creates rejected promise
1314
   * @param reason rejection value
1315
   * @returns {Promise}
1316
   */
1317
  Promise.reject = function Promise_reject(reason) {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Promise. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
1318
    return new Promise(function (resolve, reject) { reject(reason); });
1319
  };
1320
1321
  Promise.prototype = {
0 ignored issues
show
Compatibility Best Practice introduced by
You are extending the built-in type Promise. This may have unintended consequences on other objects using this built-in type. Consider subclassing instead.
Loading history...
1322
    _status: null,
1323
    _value: null,
1324
    _handlers: null,
1325
    _unhandledRejection: null,
1326
1327
    _updateStatus: function Promise__updateStatus(status, value) {
1328
      if (this._status === STATUS_RESOLVED ||
1329
          this._status === STATUS_REJECTED) {
1330
        return;
1331
      }
1332
1333
      if (status === STATUS_RESOLVED &&
1334
          Promise.isPromise(value)) {
1335
        value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
1336
                   this._updateStatus.bind(this, STATUS_REJECTED));
1337
        return;
1338
      }
1339
1340
      this._status = status;
1341
      this._value = value;
1342
1343
      if (status === STATUS_REJECTED && this._handlers.length === 0) {
1344
        this._unhandledRejection = true;
1345
        HandlerManager.addUnhandledRejection(this);
1346
      }
1347
1348
      HandlerManager.scheduleHandlers(this);
1349
    },
1350
1351
    _resolve: function Promise_resolve(value) {
1352
      this._updateStatus(STATUS_RESOLVED, value);
1353
    },
1354
1355
    _reject: function Promise_reject(reason) {
1356
      this._updateStatus(STATUS_REJECTED, reason);
1357
    },
1358
1359
    then: function Promise_then(onResolve, onReject) {
1360
      var nextPromise = new Promise(function (resolve, reject) {
1361
        this.resolve = resolve;
1362
        this.reject = reject;
1363
      });
1364
      this._handlers.push({
1365
        thisPromise: this,
1366
        onResolve: onResolve,
1367
        onReject: onReject,
1368
        nextPromise: nextPromise
1369
      });
1370
      HandlerManager.scheduleHandlers(this);
1371
      return nextPromise;
1372
    },
1373
1374
    catch: function Promise_catch(onReject) {
1375
      return this.then(undefined, onReject);
1376
    }
1377
  };
1378
1379
  globalScope.Promise = Promise;
1380
//#else
1381
//throw new Error('DOM Promise is not present');
1382
//#endif
1383
})();
1384
1385
var StatTimer = (function StatTimerClosure() {
1386
  function rpad(str, pad, length) {
1387
    while (str.length < length) {
1388
      str += pad;
1389
    }
1390
    return str;
1391
  }
1392
  function StatTimer() {
1393
    this.started = {};
1394
    this.times = [];
1395
    this.enabled = true;
1396
  }
1397
  StatTimer.prototype = {
1398
    time: function StatTimer_time(name) {
1399
      if (!this.enabled) {
1400
        return;
1401
      }
1402
      if (name in this.started) {
1403
        warn('Timer is already running for ' + name);
1404
      }
1405
      this.started[name] = Date.now();
1406
    },
1407
    timeEnd: function StatTimer_timeEnd(name) {
1408
      if (!this.enabled) {
1409
        return;
1410
      }
1411
      if (!(name in this.started)) {
1412
        warn('Timer has not been started for ' + name);
1413
      }
1414
      this.times.push({
1415
        'name': name,
1416
        'start': this.started[name],
1417
        'end': Date.now()
1418
      });
1419
      // Remove timer from started so it can be called again.
1420
      delete this.started[name];
1421
    },
1422
    toString: function StatTimer_toString() {
1423
      var i, ii;
1424
      var times = this.times;
1425
      var out = '';
1426
      // Find the longest name for padding purposes.
1427
      var longest = 0;
1428
      for (i = 0, ii = times.length; i < ii; ++i) {
1429
        var name = times[i]['name'];
1430
        if (name.length > longest) {
1431
          longest = name.length;
1432
        }
1433
      }
1434
      for (i = 0, ii = times.length; i < ii; ++i) {
1435
        var span = times[i];
1436
        var duration = span.end - span.start;
1437
        out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
1438
      }
1439
      return out;
1440
    }
1441
  };
1442
  return StatTimer;
1443
})();
1444
1445
PDFJS.createBlob = function createBlob(data, contentType) {
1446
  if (typeof Blob !== 'undefined') {
0 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1447
    return new Blob([data], { type: contentType });
1448
  }
1449
  // Blob builder is deprecated in FF14 and removed in FF18.
1450
  var bb = new MozBlobBuilder();
1451
  bb.append(data);
1452
  return bb.getBlob(contentType);
1453
};
1454
1455
PDFJS.createObjectURL = (function createObjectURLClosure() {
1456
  // Blob/createObjectURL is not available, falling back to data schema.
1457
  var digits =
1458
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
1459
1460
  return function createObjectURL(data, contentType) {
1461
    if (!PDFJS.disableCreateObjectURL &&
1462
        typeof URL !== 'undefined' && URL.createObjectURL) {
1463
      var blob = PDFJS.createBlob(data, contentType);
1464
      return URL.createObjectURL(blob);
1465
    }
1466
1467
    var buffer = 'data:' + contentType + ';base64,';
1468
    for (var i = 0, ii = data.length; i < ii; i += 3) {
1469
      var b1 = data[i] & 0xFF;
1470
      var b2 = data[i + 1] & 0xFF;
1471
      var b3 = data[i + 2] & 0xFF;
1472
      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
1473
      var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
1474
      var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
1475
      buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
1476
    }
1477
    return buffer;
1478
  };
1479
})();
1480
1481
function MessageHandler(name, comObj) {
1482
  this.name = name;
1483
  this.comObj = comObj;
1484
  this.callbackIndex = 1;
1485
  this.postMessageTransfers = true;
1486
  var callbacksCapabilities = this.callbacksCapabilities = {};
1487
  var ah = this.actionHandler = {};
1488
1489
  ah['console_log'] = [function ahConsoleLog(data) {
1490
    console.log.apply(console, data);
1491
  }];
1492
  ah['console_error'] = [function ahConsoleError(data) {
1493
    console.error.apply(console, data);
1494
  }];
1495
  ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
1496
    UnsupportedManager.notify(data);
1497
  }];
1498
1499
  comObj.onmessage = function messageHandlerComObjOnMessage(event) {
1500
    var data = event.data;
1501
    if (data.isReply) {
1502
      var callbackId = data.callbackId;
1503
      if (data.callbackId in callbacksCapabilities) {
1504
        var callback = callbacksCapabilities[callbackId];
1505
        delete callbacksCapabilities[callbackId];
1506
        if ('error' in data) {
1507
          callback.reject(data.error);
1508
        } else {
1509
          callback.resolve(data.data);
1510
        }
1511
      } else {
1512
        error('Cannot resolve callback ' + callbackId);
1513
      }
1514
    } else if (data.action in ah) {
1515
      var action = ah[data.action];
1516
      if (data.callbackId) {
1517
        Promise.resolve().then(function () {
1518
          return action[0].call(action[1], data.data);
1519
        }).then(function (result) {
1520
          comObj.postMessage({
1521
            isReply: true,
1522
            callbackId: data.callbackId,
1523
            data: result
1524
          });
1525
        }, function (reason) {
1526
          comObj.postMessage({
1527
            isReply: true,
1528
            callbackId: data.callbackId,
1529
            error: reason
1530
          });
1531
        });
1532
      } else {
1533
        action[0].call(action[1], data.data);
1534
      }
1535
    } else {
1536
      error('Unknown action from worker: ' + data.action);
1537
    }
1538
  };
1539
}
1540
1541
MessageHandler.prototype = {
1542
  on: function messageHandlerOn(actionName, handler, scope) {
1543
    var ah = this.actionHandler;
1544
    if (ah[actionName]) {
1545
      error('There is already an actionName called "' + actionName + '"');
1546
    }
1547
    ah[actionName] = [handler, scope];
1548
  },
1549
  /**
1550
   * Sends a message to the comObj to invoke the action with the supplied data.
1551
   * @param {String} actionName Action to call.
1552
   * @param {JSON} data JSON data to send.
1553
   * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
1554
   */
1555
  send: function messageHandlerSend(actionName, data, transfers) {
1556
    var message = {
1557
      action: actionName,
1558
      data: data
1559
    };
1560
    this.postMessage(message, transfers);
1561
  },
1562
  /**
1563
   * Sends a message to the comObj to invoke the action with the supplied data.
1564
   * Expects that other side will callback with the response.
1565
   * @param {String} actionName Action to call.
1566
   * @param {JSON} data JSON data to send.
1567
   * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
1568
   * @returns {Promise} Promise to be resolved with response data.
1569
   */
1570
  sendWithPromise:
1571
    function messageHandlerSendWithPromise(actionName, data, transfers) {
1572
    var callbackId = this.callbackIndex++;
0 ignored issues
show
Unused Code introduced by
The assignment to variable callbackId seems to be never used. Consider removing it.
Loading history...
1573
    var message = {
1574
      action: actionName,
1575
      data: data,
1576
      callbackId: callbackId
1577
    };
1578
    var capability = createPromiseCapability();
1579
    this.callbacksCapabilities[callbackId] = capability;
1580
    try {
1581
      this.postMessage(message, transfers);
1582
    } catch (e) {
1583
      capability.reject(e);
1584
    }
1585
    return capability.promise;
1586
  },
1587
  /**
1588
   * Sends raw message to the comObj.
1589
   * @private
1590
   * @param message {Object} Raw message.
1591
   * @param transfers List of transfers/ArrayBuffers, or undefined.
1592
   */
1593
  postMessage: function (message, transfers) {
1594
    if (transfers && this.postMessageTransfers) {
1595
      this.comObj.postMessage(message, transfers);
1596
    } else {
1597
      this.comObj.postMessage(message);
1598
    }
1599
  }
1600
};
1601
1602
function loadJpegStream(id, imageUrl, objs) {
1603
  var img = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1604
  img.onload = (function loadJpegStream_onloadClosure() {
1605
    objs.resolve(id, img);
1606
  });
1607
  img.onerror = (function loadJpegStream_onerrorClosure() {
1608
    objs.resolve(id, null);
1609
    warn('Error during JPEG image loading');
1610
  });
1611
  img.src = imageUrl;
1612
}
1613
1614
1615
/**
1616
 * The maximum allowed image size in total pixels e.g. width * height. Images
1617
 * above this value will not be drawn. Use -1 for no limit.
1618
 * @var {number}
1619
 */
1620
PDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ?
1621
                      -1 : PDFJS.maxImageSize);
1622
1623
/**
1624
 * The url of where the predefined Adobe CMaps are located. Include trailing
1625
 * slash.
1626
 * @var {string}
1627
 */
1628
PDFJS.cMapUrl = (PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl);
1629
1630
/**
1631
 * Specifies if CMaps are binary packed.
1632
 * @var {boolean}
1633
 */
1634
PDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked;
1635
1636
/**
1637
 * By default fonts are converted to OpenType fonts and loaded via font face
1638
 * rules. If disabled, the font will be rendered using a built in font renderer
1639
 * that constructs the glyphs with primitive path commands.
1640
 * @var {boolean}
1641
 */
1642
PDFJS.disableFontFace = (PDFJS.disableFontFace === undefined ?
1643
                         false : PDFJS.disableFontFace);
1644
1645
/**
1646
 * Path for image resources, mainly for annotation icons. Include trailing
1647
 * slash.
1648
 * @var {string}
1649
 */
1650
PDFJS.imageResourcesPath = (PDFJS.imageResourcesPath === undefined ?
1651
                            '' : PDFJS.imageResourcesPath);
1652
1653
/**
1654
 * Disable the web worker and run all code on the main thread. This will happen
1655
 * automatically if the browser doesn't support workers or sending typed arrays
1656
 * to workers.
1657
 * @var {boolean}
1658
 */
1659
PDFJS.disableWorker = (PDFJS.disableWorker === undefined ?
1660
                       false : PDFJS.disableWorker);
1661
1662
/**
1663
 * Path and filename of the worker file. Required when the worker is enabled in
1664
 * development mode. If unspecified in the production build, the worker will be
1665
 * loaded based on the location of the pdf.js file.
1666
 * @var {string}
1667
 */
1668
PDFJS.workerSrc = (PDFJS.workerSrc === undefined ? null : PDFJS.workerSrc);
1669
1670
/**
1671
 * Disable range request loading of PDF files. When enabled and if the server
1672
 * supports partial content requests then the PDF will be fetched in chunks.
1673
 * Enabled (false) by default.
1674
 * @var {boolean}
1675
 */
1676
PDFJS.disableRange = (PDFJS.disableRange === undefined ?
1677
                      false : PDFJS.disableRange);
1678
1679
/**
1680
 * Disable streaming of PDF file data. By default PDF.js attempts to load PDF
1681
 * in chunks. This default behavior can be disabled.
1682
 * @var {boolean}
1683
 */
1684
PDFJS.disableStream = (PDFJS.disableStream === undefined ?
1685
                       false : PDFJS.disableStream);
1686
1687
/**
1688
 * Disable pre-fetching of PDF file data. When range requests are enabled PDF.js
1689
 * will automatically keep fetching more data even if it isn't needed to display
1690
 * the current page. This default behavior can be disabled.
1691
 *
1692
 * NOTE: It is also necessary to disable streaming, see above,
1693
 *       in order for disabling of pre-fetching to work correctly.
1694
 * @var {boolean}
1695
 */
1696
PDFJS.disableAutoFetch = (PDFJS.disableAutoFetch === undefined ?
1697
                          false : PDFJS.disableAutoFetch);
1698
1699
/**
1700
 * Enables special hooks for debugging PDF.js.
1701
 * @var {boolean}
1702
 */
1703
PDFJS.pdfBug = (PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug);
1704
1705
/**
1706
 * Enables transfer usage in postMessage for ArrayBuffers.
1707
 * @var {boolean}
1708
 */
1709
PDFJS.postMessageTransfers = (PDFJS.postMessageTransfers === undefined ?
1710
                              true : PDFJS.postMessageTransfers);
1711
1712
/**
1713
 * Disables URL.createObjectURL usage.
1714
 * @var {boolean}
1715
 */
1716
PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?
1717
                                false : PDFJS.disableCreateObjectURL);
1718
1719
/**
1720
 * Disables WebGL usage.
1721
 * @var {boolean}
1722
 */
1723
PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
1724
                      true : PDFJS.disableWebGL);
1725
1726
/**
1727
 * Disables fullscreen support, and by extension Presentation Mode,
1728
 * in browsers which support the fullscreen API.
1729
 * @var {boolean}
1730
 */
1731
PDFJS.disableFullscreen = (PDFJS.disableFullscreen === undefined ?
1732
                           false : PDFJS.disableFullscreen);
1733
1734
/**
1735
 * Enables CSS only zooming.
1736
 * @var {boolean}
1737
 */
1738
PDFJS.useOnlyCssZoom = (PDFJS.useOnlyCssZoom === undefined ?
1739
                        false : PDFJS.useOnlyCssZoom);
1740
1741
/**
1742
 * Controls the logging level.
1743
 * The constants from PDFJS.VERBOSITY_LEVELS should be used:
1744
 * - errors
1745
 * - warnings [default]
1746
 * - infos
1747
 * @var {number}
1748
 */
1749
PDFJS.verbosity = (PDFJS.verbosity === undefined ?
1750
                   PDFJS.VERBOSITY_LEVELS.warnings : PDFJS.verbosity);
1751
1752
/**
1753
 * The maximum supported canvas size in total pixels e.g. width * height.
1754
 * The default value is 4096 * 4096. Use -1 for no limit.
1755
 * @var {number}
1756
 */
1757
PDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ?
1758
                         16777216 : PDFJS.maxCanvasPixels);
1759
1760
/**
1761
 * Opens external links in a new window if enabled. The default behavior opens
1762
 * external links in the PDF.js window.
1763
 * @var {boolean}
1764
 */
1765
PDFJS.openExternalLinksInNewWindow = (
1766
  PDFJS.openExternalLinksInNewWindow === undefined ?
1767
    false : PDFJS.openExternalLinksInNewWindow);
1768
1769
/**
1770
 * Document initialization / loading parameters object.
1771
 *
1772
 * @typedef {Object} DocumentInitParameters
1773
 * @property {string}     url   - The URL of the PDF.
1774
 * @property {TypedArray|Array|string} data - Binary PDF data. Use typed arrays
1775
 *   (Uint8Array) to improve the memory usage. If PDF data is BASE64-encoded,
1776
 *   use atob() to convert it to a binary string first.
1777
 * @property {Object}     httpHeaders - Basic authentication headers.
1778
 * @property {boolean}    withCredentials - Indicates whether or not cross-site
1779
 *   Access-Control requests should be made using credentials such as cookies
1780
 *   or authorization headers. The default is false.
1781
 * @property {string}     password - For decrypting password-protected PDFs.
1782
 * @property {TypedArray} initialData - A typed array with the first portion or
1783
 *   all of the pdf data. Used by the extension since some data is already
1784
 *   loaded before the switch to range requests.
1785
 * @property {number}     length - The PDF file length. It's used for progress
1786
 *   reports and range requests operations.
1787
 * @property {PDFDataRangeTransport} range
1788
 */
1789
1790
/**
1791
 * @typedef {Object} PDFDocumentStats
1792
 * @property {Array} streamTypes - Used stream types in the document (an item
1793
 *   is set to true if specific stream ID was used in the document).
1794
 * @property {Array} fontTypes - Used font type in the document (an item is set
1795
 *   to true if specific font ID was used in the document).
1796
 */
1797
1798
/**
1799
 * This is the main entry point for loading a PDF and interacting with it.
1800
 * NOTE: If a URL is used to fetch the PDF data a standard XMLHttpRequest(XHR)
1801
 * is used, which means it must follow the same origin rules that any XHR does
1802
 * e.g. No cross domain requests without CORS.
1803
 *
1804
 * @param {string|TypedArray|DocumentInitParameters|PDFDataRangeTransport} src
1805
 * Can be a url to where a PDF is located, a typed array (Uint8Array)
1806
 * already populated with data or parameter object.
1807
 *
1808
 * @param {PDFDataRangeTransport} pdfDataRangeTransport (deprecated) It is used
1809
 * if you want to manually serve range requests for data in the PDF.
1810
 *
1811
 * @param {function} passwordCallback (deprecated) It is used to request a
1812
 * password if wrong or no password was provided. The callback receives two
1813
 * parameters: function that needs to be called with new password and reason
1814
 * (see {PasswordResponses}).
1815
 *
1816
 * @param {function} progressCallback (deprecated) It is used to be able to
1817
 * monitor the loading progress of the PDF file (necessary to implement e.g.
1818
 * a loading bar). The callback receives an {Object} with the properties:
1819
 * {number} loaded and {number} total.
1820
 *
1821
 * @return {PDFDocumentLoadingTask}
1822
 */
1823
PDFJS.getDocument = function getDocument(src,
1824
                                         pdfDataRangeTransport,
1825
                                         passwordCallback,
1826
                                         progressCallback) {
1827
  var task = new PDFDocumentLoadingTask();
1828
1829
  // Support of the obsolete arguments (for compatibility with API v1.0)
1830
  if (pdfDataRangeTransport) {
1831
    if (!(pdfDataRangeTransport instanceof PDFDataRangeTransport)) {
1832
      // Not a PDFDataRangeTransport instance, trying to add missing properties.
1833
      pdfDataRangeTransport = Object.create(pdfDataRangeTransport);
1834
      pdfDataRangeTransport.length = src.length;
1835
      pdfDataRangeTransport.initialData = src.initialData;
1836
    }
1837
    src = Object.create(src);
1838
    src.range = pdfDataRangeTransport;
1839
  }
1840
  task.onPassword = passwordCallback || null;
1841
  task.onProgress = progressCallback || null;
1842
1843
  var workerInitializedCapability, transport;
1844
  var source;
1845
  if (typeof src === 'string') {
1846
    source = { url: src };
1847
  } else if (isArrayBuffer(src)) {
1848
    source = { data: src };
1849
  } else if (src instanceof PDFDataRangeTransport) {
1850
    source = { range: src };
1851
  } else {
1852
    if (typeof src !== 'object') {
1853
      error('Invalid parameter in getDocument, need either Uint8Array, ' +
1854
        'string or a parameter object');
1855
    }
1856
    if (!src.url && !src.data && !src.range) {
1857
      error('Invalid parameter object: need either .data, .range or .url');
1858
    }
1859
1860
    source = src;
1861
  }
1862
1863
  var params = {};
1864
  for (var key in source) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
1865
    if (key === 'url' && typeof window !== 'undefined') {
1866
      // The full path is required in the 'url' field.
1867
      params[key] = combineUrl(window.location.href, source[key]);
1868
      continue;
1869
    } else if (key === 'range') {
1870
      continue;
1871
    } else if (key === 'data' && !(source[key] instanceof Uint8Array)) {
1872
      // Converting string or array-like data to Uint8Array.
1873
      var pdfBytes = source[key];
1874
      if (typeof pdfBytes === 'string') {
1875
        params[key] = stringToBytes(pdfBytes);
1876
      } else if (typeof pdfBytes === 'object' && pdfBytes !== null &&
1877
                 !isNaN(pdfBytes.length)) {
1878
        params[key] = new Uint8Array(pdfBytes);
1879
      } else {
1880
        error('Invalid PDF binary data: either typed array, string or ' +
1881
              'array-like object is expected in the data property.');
1882
      }
1883
      continue;
1884
    }
1885
    params[key] = source[key];
1886
  }
1887
1888
  workerInitializedCapability = createPromiseCapability();
1889
  transport = new WorkerTransport(workerInitializedCapability, source.range);
1890
  workerInitializedCapability.promise.then(function transportInitialized() {
1891
    transport.fetchDocument(task, params);
1892
  });
1893
1894
  return task;
1895
};
1896
1897
/**
1898
 * PDF document loading operation.
1899
 * @class
1900
 */
1901
var PDFDocumentLoadingTask = (function PDFDocumentLoadingTaskClosure() {
1902
  /** @constructs PDFDocumentLoadingTask */
1903
  function PDFDocumentLoadingTask() {
1904
    this._capability = createPromiseCapability();
1905
1906
    /**
1907
     * Callback to request a password if wrong or no password was provided.
1908
     * The callback receives two parameters: function that needs to be called
1909
     * with new password and reason (see {PasswordResponses}).
1910
     */
1911
    this.onPassword = null;
1912
1913
    /**
1914
     * Callback to be able to monitor the loading progress of the PDF file
1915
     * (necessary to implement e.g. a loading bar). The callback receives
1916
     * an {Object} with the properties: {number} loaded and {number} total.
1917
     */
1918
    this.onProgress = null;
1919
  }
1920
1921
  PDFDocumentLoadingTask.prototype =
1922
      /** @lends PDFDocumentLoadingTask.prototype */ {
1923
    /**
1924
     * @return {Promise}
1925
     */
1926
    get promise() {
1927
      return this._capability.promise;
1928
    },
1929
1930
    // TODO add cancel or abort method
1931
1932
    /**
1933
     * Registers callbacks to indicate the document loading completion.
1934
     *
1935
     * @param {function} onFulfilled The callback for the loading completion.
1936
     * @param {function} onRejected The callback for the loading failure.
1937
     * @return {Promise} A promise that is resolved after the onFulfilled or
1938
     *                   onRejected callback.
1939
     */
1940
    then: function PDFDocumentLoadingTask_then(onFulfilled, onRejected) {
0 ignored issues
show
Unused Code introduced by
The parameter onRejected is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter onFulfilled is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1941
      return this.promise.then.apply(this.promise, arguments);
1942
    }
1943
  };
1944
1945
  return PDFDocumentLoadingTask;
1946
})();
1947
1948
/**
1949
 * Abstract class to support range requests file loading.
1950
 * @class
1951
 */
1952
var PDFDataRangeTransport = (function pdfDataRangeTransportClosure() {
1953
  /**
1954
   * @constructs PDFDataRangeTransport
1955
   * @param {number} length
1956
   * @param {Uint8Array} initialData
1957
   */
1958
  function PDFDataRangeTransport(length, initialData) {
1959
    this.length = length;
1960
    this.initialData = initialData;
1961
1962
    this._rangeListeners = [];
1963
    this._progressListeners = [];
1964
    this._progressiveReadListeners = [];
1965
    this._readyCapability = createPromiseCapability();
1966
  }
1967
  PDFDataRangeTransport.prototype =
1968
      /** @lends PDFDataRangeTransport.prototype */ {
1969
    addRangeListener:
1970
        function PDFDataRangeTransport_addRangeListener(listener) {
1971
      this._rangeListeners.push(listener);
1972
    },
1973
1974
    addProgressListener:
1975
        function PDFDataRangeTransport_addProgressListener(listener) {
1976
      this._progressListeners.push(listener);
1977
    },
1978
1979
    addProgressiveReadListener:
1980
        function PDFDataRangeTransport_addProgressiveReadListener(listener) {
1981
      this._progressiveReadListeners.push(listener);
1982
    },
1983
1984
    onDataRange: function PDFDataRangeTransport_onDataRange(begin, chunk) {
1985
      var listeners = this._rangeListeners;
1986
      for (var i = 0, n = listeners.length; i < n; ++i) {
1987
        listeners[i](begin, chunk);
1988
      }
1989
    },
1990
1991
    onDataProgress: function PDFDataRangeTransport_onDataProgress(loaded) {
1992
      this._readyCapability.promise.then(function () {
1993
        var listeners = this._progressListeners;
1994
        for (var i = 0, n = listeners.length; i < n; ++i) {
1995
          listeners[i](loaded);
1996
        }
1997
      }.bind(this));
1998
    },
1999
2000
    onDataProgressiveRead:
2001
        function PDFDataRangeTransport_onDataProgress(chunk) {
2002
      this._readyCapability.promise.then(function () {
2003
        var listeners = this._progressiveReadListeners;
2004
        for (var i = 0, n = listeners.length; i < n; ++i) {
2005
          listeners[i](chunk);
2006
        }
2007
      }.bind(this));
2008
    },
2009
2010
    transportReady: function PDFDataRangeTransport_transportReady() {
2011
      this._readyCapability.resolve();
2012
    },
2013
2014
    requestDataRange:
2015
        function PDFDataRangeTransport_requestDataRange(begin, end) {
0 ignored issues
show
Unused Code introduced by
The parameter begin is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter end is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2016
      throw new Error('Abstract method PDFDataRangeTransport.requestDataRange');
2017
    }
2018
  };
2019
  return PDFDataRangeTransport;
2020
})();
2021
2022
PDFJS.PDFDataRangeTransport = PDFDataRangeTransport;
2023
2024
/**
2025
 * Proxy to a PDFDocument in the worker thread. Also, contains commonly used
2026
 * properties that can be read synchronously.
2027
 * @class
2028
 */
2029
var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
2030
  function PDFDocumentProxy(pdfInfo, transport) {
2031
    this.pdfInfo = pdfInfo;
2032
    this.transport = transport;
2033
  }
2034
  PDFDocumentProxy.prototype = /** @lends PDFDocumentProxy.prototype */ {
2035
    /**
2036
     * @return {number} Total number of pages the PDF contains.
2037
     */
2038
    get numPages() {
2039
      return this.pdfInfo.numPages;
2040
    },
2041
    /**
2042
     * @return {string} A unique ID to identify a PDF. Not guaranteed to be
2043
     * unique.
2044
     */
2045
    get fingerprint() {
2046
      return this.pdfInfo.fingerprint;
2047
    },
2048
    /**
2049
     * @param {number} pageNumber The page number to get. The first page is 1.
2050
     * @return {Promise} A promise that is resolved with a {@link PDFPageProxy}
2051
     * object.
2052
     */
2053
    getPage: function PDFDocumentProxy_getPage(pageNumber) {
2054
      return this.transport.getPage(pageNumber);
2055
    },
2056
    /**
2057
     * @param {{num: number, gen: number}} ref The page reference. Must have
2058
     *   the 'num' and 'gen' properties.
2059
     * @return {Promise} A promise that is resolved with the page index that is
2060
     * associated with the reference.
2061
     */
2062
    getPageIndex: function PDFDocumentProxy_getPageIndex(ref) {
2063
      return this.transport.getPageIndex(ref);
2064
    },
2065
    /**
2066
     * @return {Promise} A promise that is resolved with a lookup table for
2067
     * mapping named destinations to reference numbers.
2068
     *
2069
     * This can be slow for large documents: use getDestination instead
2070
     */
2071
    getDestinations: function PDFDocumentProxy_getDestinations() {
2072
      return this.transport.getDestinations();
2073
    },
2074
    /**
2075
     * @param {string} id The named destination to get.
2076
     * @return {Promise} A promise that is resolved with all information
2077
     * of the given named destination.
2078
     */
2079
    getDestination: function PDFDocumentProxy_getDestination(id) {
2080
      return this.transport.getDestination(id);
2081
    },
2082
    /**
2083
     * @return {Promise} A promise that is resolved with a lookup table for
2084
     * mapping named attachments to their content.
2085
     */
2086
    getAttachments: function PDFDocumentProxy_getAttachments() {
2087
      return this.transport.getAttachments();
2088
    },
2089
    /**
2090
     * @return {Promise} A promise that is resolved with an array of all the
2091
     * JavaScript strings in the name tree.
2092
     */
2093
    getJavaScript: function PDFDocumentProxy_getJavaScript() {
2094
      return this.transport.getJavaScript();
2095
    },
2096
    /**
2097
     * @return {Promise} A promise that is resolved with an {Array} that is a
2098
     * tree outline (if it has one) of the PDF. The tree is in the format of:
2099
     * [
2100
     *  {
2101
     *   title: string,
2102
     *   bold: boolean,
2103
     *   italic: boolean,
2104
     *   color: rgb array,
2105
     *   dest: dest obj,
2106
     *   items: array of more items like this
2107
     *  },
2108
     *  ...
2109
     * ].
2110
     */
2111
    getOutline: function PDFDocumentProxy_getOutline() {
2112
      return this.transport.getOutline();
2113
    },
2114
    /**
2115
     * @return {Promise} A promise that is resolved with an {Object} that has
2116
     * info and metadata properties.  Info is an {Object} filled with anything
2117
     * available in the information dictionary and similarly metadata is a
2118
     * {Metadata} object with information from the metadata section of the PDF.
2119
     */
2120
    getMetadata: function PDFDocumentProxy_getMetadata() {
2121
      return this.transport.getMetadata();
2122
    },
2123
    /**
2124
     * @return {Promise} A promise that is resolved with a TypedArray that has
2125
     * the raw data from the PDF.
2126
     */
2127
    getData: function PDFDocumentProxy_getData() {
2128
      return this.transport.getData();
2129
    },
2130
    /**
2131
     * @return {Promise} A promise that is resolved when the document's data
2132
     * is loaded. It is resolved with an {Object} that contains the length
2133
     * property that indicates size of the PDF data in bytes.
2134
     */
2135
    getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() {
2136
      return this.transport.downloadInfoCapability.promise;
2137
    },
2138
    /**
2139
     * @return {Promise} A promise this is resolved with current stats about
2140
     * document structures (see {@link PDFDocumentStats}).
2141
     */
2142
    getStats: function PDFDocumentProxy_getStats() {
2143
      return this.transport.getStats();
2144
    },
2145
    /**
2146
     * Cleans up resources allocated by the document, e.g. created @font-face.
2147
     */
2148
    cleanup: function PDFDocumentProxy_cleanup() {
2149
      this.transport.startCleanup();
2150
    },
2151
    /**
2152
     * Destroys current document instance and terminates worker.
2153
     */
2154
    destroy: function PDFDocumentProxy_destroy() {
2155
      this.transport.destroy();
2156
    }
2157
  };
2158
  return PDFDocumentProxy;
2159
})();
2160
2161
/**
2162
 * Page text content.
2163
 *
2164
 * @typedef {Object} TextContent
2165
 * @property {array} items - array of {@link TextItem}
2166
 * @property {Object} styles - {@link TextStyles} objects, indexed by font
2167
 *                    name.
2168
 */
2169
2170
/**
2171
 * Page text content part.
2172
 *
2173
 * @typedef {Object} TextItem
2174
 * @property {string} str - text content.
2175
 * @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'.
2176
 * @property {array} transform - transformation matrix.
2177
 * @property {number} width - width in device space.
2178
 * @property {number} height - height in device space.
2179
 * @property {string} fontName - font name used by pdf.js for converted font.
2180
 */
2181
2182
/**
2183
 * Text style.
2184
 *
2185
 * @typedef {Object} TextStyle
2186
 * @property {number} ascent - font ascent.
2187
 * @property {number} descent - font descent.
2188
 * @property {boolean} vertical - text is in vertical mode.
2189
 * @property {string} fontFamily - possible font family
2190
 */
2191
2192
/**
2193
 * Page render parameters.
2194
 *
2195
 * @typedef {Object} RenderParameters
2196
 * @property {Object} canvasContext - A 2D context of a DOM Canvas object.
2197
 * @property {PDFJS.PageViewport} viewport - Rendering viewport obtained by
2198
 *                                calling of PDFPage.getViewport method.
2199
 * @property {string} intent - Rendering intent, can be 'display' or 'print'
2200
 *                    (default value is 'display').
2201
 * @property {Object} imageLayer - (optional) An object that has beginLayout,
2202
 *                    endLayout and appendImage functions.
2203
 * @property {function} continueCallback - (deprecated) A function that will be
2204
 *                      called each time the rendering is paused.  To continue
2205
 *                      rendering call the function that is the first argument
2206
 *                      to the callback.
2207
 */
2208
2209
/**
2210
 * PDF page operator list.
2211
 *
2212
 * @typedef {Object} PDFOperatorList
2213
 * @property {Array} fnArray - Array containing the operator functions.
2214
 * @property {Array} argsArray - Array containing the arguments of the
2215
 *                               functions.
2216
 */
2217
2218
/**
2219
 * Proxy to a PDFPage in the worker thread.
2220
 * @class
2221
 */
2222
var PDFPageProxy = (function PDFPageProxyClosure() {
2223
  function PDFPageProxy(pageIndex, pageInfo, transport) {
2224
    this.pageIndex = pageIndex;
2225
    this.pageInfo = pageInfo;
2226
    this.transport = transport;
2227
    this.stats = new StatTimer();
2228
    this.stats.enabled = !!globalScope.PDFJS.enableStats;
2229
    this.commonObjs = transport.commonObjs;
2230
    this.objs = new PDFObjects();
2231
    this.cleanupAfterRender = false;
2232
    this.pendingDestroy = false;
2233
    this.intentStates = {};
2234
  }
2235
  PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ {
2236
    /**
2237
     * @return {number} Page number of the page. First page is 1.
2238
     */
2239
    get pageNumber() {
2240
      return this.pageIndex + 1;
2241
    },
2242
    /**
2243
     * @return {number} The number of degrees the page is rotated clockwise.
2244
     */
2245
    get rotate() {
2246
      return this.pageInfo.rotate;
2247
    },
2248
    /**
2249
     * @return {Object} The reference that points to this page. It has 'num' and
2250
     * 'gen' properties.
2251
     */
2252
    get ref() {
2253
      return this.pageInfo.ref;
2254
    },
2255
    /**
2256
     * @return {Array} An array of the visible portion of the PDF page in the
2257
     * user space units - [x1, y1, x2, y2].
2258
     */
2259
    get view() {
2260
      return this.pageInfo.view;
2261
    },
2262
    /**
2263
     * @param {number} scale The desired scale of the viewport.
2264
     * @param {number} rotate Degrees to rotate the viewport. If omitted this
2265
     * defaults to the page rotation.
2266
     * @return {PDFJS.PageViewport} Contains 'width' and 'height' properties
2267
     * along with transforms required for rendering.
2268
     */
2269
    getViewport: function PDFPageProxy_getViewport(scale, rotate) {
2270
      if (arguments.length < 2) {
2271
        rotate = this.rotate;
2272
      }
2273
      return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0);
2274
    },
2275
    /**
2276
     * @return {Promise} A promise that is resolved with an {Array} of the
2277
     * annotation objects.
2278
     */
2279
    getAnnotations: function PDFPageProxy_getAnnotations() {
2280
      if (this.annotationsPromise) {
2281
        return this.annotationsPromise;
2282
      }
2283
2284
      var promise = this.transport.getAnnotations(this.pageIndex);
2285
      this.annotationsPromise = promise;
2286
      return promise;
2287
    },
2288
    /**
2289
     * Begins the process of rendering a page to the desired context.
2290
     * @param {RenderParameters} params Page render parameters.
2291
     * @return {RenderTask} An object that contains the promise, which
2292
     *                      is resolved when the page finishes rendering.
2293
     */
2294
    render: function PDFPageProxy_render(params) {
2295
      var stats = this.stats;
2296
      stats.time('Overall');
2297
2298
      // If there was a pending destroy cancel it so no cleanup happens during
2299
      // this call to render.
2300
      this.pendingDestroy = false;
2301
2302
      var renderingIntent = (params.intent === 'print' ? 'print' : 'display');
2303
2304
      if (!this.intentStates[renderingIntent]) {
2305
        this.intentStates[renderingIntent] = {};
2306
      }
2307
      var intentState = this.intentStates[renderingIntent];
2308
2309
      // If there's no displayReadyCapability yet, then the operatorList
2310
      // was never requested before. Make the request and create the promise.
2311
      if (!intentState.displayReadyCapability) {
2312
        intentState.receivingOperatorList = true;
2313
        intentState.displayReadyCapability = createPromiseCapability();
2314
        intentState.operatorList = {
2315
          fnArray: [],
2316
          argsArray: [],
2317
          lastChunk: false
2318
        };
2319
2320
        this.stats.time('Page Request');
2321
        this.transport.messageHandler.send('RenderPageRequest', {
2322
          pageIndex: this.pageNumber - 1,
2323
          intent: renderingIntent
2324
        });
2325
      }
2326
2327
      var internalRenderTask = new InternalRenderTask(complete, params,
2328
                                                      this.objs,
2329
                                                      this.commonObjs,
2330
                                                      intentState.operatorList,
2331
                                                      this.pageNumber);
2332
      if (!intentState.renderTasks) {
2333
        intentState.renderTasks = [];
2334
      }
2335
      intentState.renderTasks.push(internalRenderTask);
2336
      var renderTask = internalRenderTask.task;
2337
2338
      // Obsolete parameter support
2339
      if (params.continueCallback) {
2340
        renderTask.onContinue = params.continueCallback;
2341
      }
2342
2343
      var self = this;
2344
      intentState.displayReadyCapability.promise.then(
2345
        function pageDisplayReadyPromise(transparency) {
2346
          if (self.pendingDestroy) {
2347
            complete();
2348
            return;
2349
          }
2350
          stats.time('Rendering');
2351
          internalRenderTask.initalizeGraphics(transparency);
2352
          internalRenderTask.operatorListChanged();
2353
        },
2354
        function pageDisplayReadPromiseError(reason) {
2355
          complete(reason);
2356
        }
2357
      );
2358
2359
      function complete(error) {
2360
        var i = intentState.renderTasks.indexOf(internalRenderTask);
2361
        if (i >= 0) {
2362
          intentState.renderTasks.splice(i, 1);
2363
        }
2364
2365
        if (self.cleanupAfterRender) {
2366
          self.pendingDestroy = true;
2367
        }
2368
        self._tryDestroy();
2369
2370
        if (error) {
2371
          internalRenderTask.capability.reject(error);
2372
        } else {
2373
          internalRenderTask.capability.resolve();
2374
        }
2375
        stats.timeEnd('Rendering');
2376
        stats.timeEnd('Overall');
2377
      }
2378
2379
      return renderTask;
2380
    },
2381
2382
    /**
2383
     * @return {Promise} A promise resolved with an {@link PDFOperatorList}
2384
     * object that represents page's operator list.
2385
     */
2386
    getOperatorList: function PDFPageProxy_getOperatorList() {
2387
      function operatorListChanged() {
2388
        if (intentState.operatorList.lastChunk) {
2389
          intentState.opListReadCapability.resolve(intentState.operatorList);
2390
        }
2391
      }
2392
2393
      var renderingIntent = 'oplist';
2394
      if (!this.intentStates[renderingIntent]) {
2395
        this.intentStates[renderingIntent] = {};
2396
      }
2397
      var intentState = this.intentStates[renderingIntent];
2398
2399
      if (!intentState.opListReadCapability) {
2400
        var opListTask = {};
2401
        opListTask.operatorListChanged = operatorListChanged;
2402
        intentState.receivingOperatorList = true;
2403
        intentState.opListReadCapability = createPromiseCapability();
2404
        intentState.renderTasks = [];
2405
        intentState.renderTasks.push(opListTask);
2406
        intentState.operatorList = {
2407
          fnArray: [],
2408
          argsArray: [],
2409
          lastChunk: false
2410
        };
2411
2412
        this.transport.messageHandler.send('RenderPageRequest', {
2413
          pageIndex: this.pageIndex,
2414
          intent: renderingIntent
2415
        });
2416
      }
2417
      return intentState.opListReadCapability.promise;
2418
    },
2419
2420
    /**
2421
     * @return {Promise} That is resolved a {@link TextContent}
2422
     * object that represent the page text content.
2423
     */
2424
    getTextContent: function PDFPageProxy_getTextContent() {
2425
      return this.transport.messageHandler.sendWithPromise('GetTextContent', {
2426
        pageIndex: this.pageNumber - 1
2427
      });
2428
    },
2429
    /**
2430
     * Destroys resources allocated by the page.
2431
     */
2432
    destroy: function PDFPageProxy_destroy() {
2433
      this.pendingDestroy = true;
2434
      this._tryDestroy();
2435
    },
2436
    /**
2437
     * For internal use only. Attempts to clean up if rendering is in a state
2438
     * where that's possible.
2439
     * @ignore
2440
     */
2441
    _tryDestroy: function PDFPageProxy__destroy() {
2442
      if (!this.pendingDestroy ||
2443
          Object.keys(this.intentStates).some(function(intent) {
2444
            var intentState = this.intentStates[intent];
2445
            return (intentState.renderTasks.length !== 0 ||
2446
                    intentState.receivingOperatorList);
2447
          }, this)) {
2448
        return;
2449
      }
2450
2451
      Object.keys(this.intentStates).forEach(function(intent) {
2452
        delete this.intentStates[intent];
2453
      }, this);
2454
      this.objs.clear();
2455
      this.annotationsPromise = null;
2456
      this.pendingDestroy = false;
2457
    },
2458
    /**
2459
     * For internal use only.
2460
     * @ignore
2461
     */
2462
    _startRenderPage: function PDFPageProxy_startRenderPage(transparency,
2463
                                                            intent) {
2464
      var intentState = this.intentStates[intent];
2465
      // TODO Refactor RenderPageRequest to separate rendering
2466
      // and operator list logic
2467
      if (intentState.displayReadyCapability) {
2468
        intentState.displayReadyCapability.resolve(transparency);
2469
      }
2470
    },
2471
    /**
2472
     * For internal use only.
2473
     * @ignore
2474
     */
2475
    _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,
2476
                                                            intent) {
2477
      var intentState = this.intentStates[intent];
2478
      var i, ii;
2479
      // Add the new chunk to the current operator list.
2480
      for (i = 0, ii = operatorListChunk.length; i < ii; i++) {
2481
        intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
2482
        intentState.operatorList.argsArray.push(
2483
          operatorListChunk.argsArray[i]);
2484
      }
2485
      intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
2486
2487
      // Notify all the rendering tasks there are more operators to be consumed.
2488
      for (i = 0; i < intentState.renderTasks.length; i++) {
2489
        intentState.renderTasks[i].operatorListChanged();
2490
      }
2491
2492
      if (operatorListChunk.lastChunk) {
2493
        intentState.receivingOperatorList = false;
2494
        this._tryDestroy();
2495
      }
2496
    }
2497
  };
2498
  return PDFPageProxy;
2499
})();
2500
2501
/**
2502
 * For internal use only.
2503
 * @ignore
2504
 */
2505
var WorkerTransport = (function WorkerTransportClosure() {
2506
  function WorkerTransport(workerInitializedCapability, pdfDataRangeTransport) {
2507
    this.pdfDataRangeTransport = pdfDataRangeTransport;
2508
    this.workerInitializedCapability = workerInitializedCapability;
2509
    this.commonObjs = new PDFObjects();
2510
2511
    this.loadingTask = null;
2512
2513
    this.pageCache = [];
2514
    this.pagePromises = [];
2515
    this.downloadInfoCapability = createPromiseCapability();
2516
2517
    // If worker support isn't disabled explicit and the browser has worker
2518
    // support, create a new web worker and test if it/the browser fullfills
2519
    // all requirements to run parts of pdf.js in a web worker.
2520
    // Right now, the requirement is, that an Uint8Array is still an Uint8Array
2521
    // as it arrives on the worker. Chrome added this with version 15.
2522
//#if !SINGLE_FILE
2523
    if (!globalScope.PDFJS.disableWorker && typeof Worker !== 'undefined') {
0 ignored issues
show
Bug introduced by
The variable Worker seems to be never declared. If this is a global, consider adding a /** global: Worker */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
2524
      var workerSrc = PDFJS.workerSrc;
2525
      if (!workerSrc) {
2526
        error('No PDFJS.workerSrc specified');
2527
      }
2528
2529
      try {
2530
        // Some versions of FF can't create a worker on localhost, see:
2531
        // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
2532
        var worker = new Worker(workerSrc);
2533
        var messageHandler = new MessageHandler('main', worker);
2534
        this.messageHandler = messageHandler;
2535
2536
        messageHandler.on('test', function transportTest(data) {
2537
          var supportTypedArray = data && data.supportTypedArray;
2538
          if (supportTypedArray) {
2539
            this.worker = worker;
2540
            if (!data.supportTransfers) {
2541
              PDFJS.postMessageTransfers = false;
2542
            }
2543
            this.setupMessageHandler(messageHandler);
2544
            workerInitializedCapability.resolve();
2545
          } else {
2546
            this.setupFakeWorker();
2547
          }
2548
        }.bind(this));
2549
2550
        var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
2551
        // Some versions of Opera throw a DATA_CLONE_ERR on serializing the
2552
        // typed array. Also, checking if we can use transfers.
2553
        try {
2554
          messageHandler.send('test', testObj, [testObj.buffer]);
2555
        } catch (ex) {
2556
          info('Cannot use postMessage transfers');
2557
          testObj[0] = 0;
2558
          messageHandler.send('test', testObj);
2559
        }
2560
        return;
2561
      } catch (e) {
2562
        info('The worker has been disabled.');
2563
      }
2564
    }
2565
//#endif
2566
    // Either workers are disabled, not supported or have thrown an exception.
2567
    // Thus, we fallback to a faked worker.
2568
    this.setupFakeWorker();
2569
  }
2570
  WorkerTransport.prototype = {
2571
    destroy: function WorkerTransport_destroy() {
2572
      this.pageCache = [];
2573
      this.pagePromises = [];
2574
      var self = this;
2575
      this.messageHandler.sendWithPromise('Terminate', null).then(function () {
2576
        FontLoader.clear();
2577
        if (self.worker) {
2578
          self.worker.terminate();
2579
        }
2580
      });
2581
    },
2582
2583
    setupFakeWorker: function WorkerTransport_setupFakeWorker() {
2584
      globalScope.PDFJS.disableWorker = true;
2585
2586
      if (!PDFJS.fakeWorkerFilesLoadedCapability) {
2587
        PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability();
2588
        // In the developer build load worker_loader which in turn loads all the
2589
        // other files and resolves the promise. In production only the
2590
        // pdf.worker.js file is needed.
2591
//#if !PRODUCTION
2592
        Util.loadScript(PDFJS.workerSrc);
2593
//#endif
2594
//#if PRODUCTION && SINGLE_FILE
2595
//      PDFJS.fakeWorkerFilesLoadedCapability.resolve();
2596
//#endif
2597
//#if PRODUCTION && !SINGLE_FILE
2598
//      Util.loadScript(PDFJS.workerSrc, function() {
2599
//        PDFJS.fakeWorkerFilesLoadedCapability.resolve();
2600
//      });
2601
//#endif
2602
      }
2603
      PDFJS.fakeWorkerFilesLoadedCapability.promise.then(function () {
2604
        warn('Setting up fake worker.');
2605
        // If we don't use a worker, just post/sendMessage to the main thread.
2606
        var fakeWorker = {
2607
          postMessage: function WorkerTransport_postMessage(obj) {
2608
            fakeWorker.onmessage({data: obj});
2609
          },
2610
          terminate: function WorkerTransport_terminate() {}
2611
        };
2612
2613
        var messageHandler = new MessageHandler('main', fakeWorker);
2614
        this.setupMessageHandler(messageHandler);
2615
2616
        // If the main thread is our worker, setup the handling for the messages
2617
        // the main thread sends to it self.
2618
        PDFJS.WorkerMessageHandler.setup(messageHandler);
2619
2620
        this.workerInitializedCapability.resolve();
2621
      }.bind(this));
2622
    },
2623
2624
    setupMessageHandler:
2625
      function WorkerTransport_setupMessageHandler(messageHandler) {
2626
      this.messageHandler = messageHandler;
2627
2628
      function updatePassword(password) {
2629
        messageHandler.send('UpdatePassword', password);
2630
      }
2631
2632
      var pdfDataRangeTransport = this.pdfDataRangeTransport;
2633
      if (pdfDataRangeTransport) {
2634
        pdfDataRangeTransport.addRangeListener(function(begin, chunk) {
2635
          messageHandler.send('OnDataRange', {
2636
            begin: begin,
2637
            chunk: chunk
2638
          });
2639
        });
2640
2641
        pdfDataRangeTransport.addProgressListener(function(loaded) {
2642
          messageHandler.send('OnDataProgress', {
2643
            loaded: loaded
2644
          });
2645
        });
2646
2647
        pdfDataRangeTransport.addProgressiveReadListener(function(chunk) {
2648
          messageHandler.send('OnDataRange', {
2649
            chunk: chunk
2650
          });
2651
        });
2652
2653
        messageHandler.on('RequestDataRange',
2654
          function transportDataRange(data) {
2655
            pdfDataRangeTransport.requestDataRange(data.begin, data.end);
2656
          }, this);
2657
      }
2658
2659
      messageHandler.on('GetDoc', function transportDoc(data) {
2660
        var pdfInfo = data.pdfInfo;
2661
        this.numPages = data.pdfInfo.numPages;
2662
        var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
2663
        this.pdfDocument = pdfDocument;
2664
        this.loadingTask._capability.resolve(pdfDocument);
2665
      }, this);
2666
2667
      messageHandler.on('NeedPassword',
2668
                        function transportNeedPassword(exception) {
2669
        var loadingTask = this.loadingTask;
2670
        if (loadingTask.onPassword) {
2671
          return loadingTask.onPassword(updatePassword,
2672
                                        PasswordResponses.NEED_PASSWORD);
2673
        }
2674
        loadingTask._capability.reject(
2675
          new PasswordException(exception.message, exception.code));
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
2676
      }, this);
2677
2678
      messageHandler.on('IncorrectPassword',
2679
                        function transportIncorrectPassword(exception) {
2680
        var loadingTask = this.loadingTask;
2681
        if (loadingTask.onPassword) {
2682
          return loadingTask.onPassword(updatePassword,
2683
                                        PasswordResponses.INCORRECT_PASSWORD);
2684
        }
2685
        loadingTask._capability.reject(
2686
          new PasswordException(exception.message, exception.code));
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
2687
      }, this);
2688
2689
      messageHandler.on('InvalidPDF', function transportInvalidPDF(exception) {
2690
        this.loadingTask._capability.reject(
2691
          new InvalidPDFException(exception.message));
2692
      }, this);
2693
2694
      messageHandler.on('MissingPDF', function transportMissingPDF(exception) {
2695
        this.loadingTask._capability.reject(
2696
          new MissingPDFException(exception.message));
2697
      }, this);
2698
2699
      messageHandler.on('UnexpectedResponse',
2700
                        function transportUnexpectedResponse(exception) {
2701
        this.loadingTask._capability.reject(
2702
          new UnexpectedResponseException(exception.message, exception.status));
2703
      }, this);
2704
2705
      messageHandler.on('UnknownError',
2706
                        function transportUnknownError(exception) {
2707
        this.loadingTask._capability.reject(
2708
          new UnknownErrorException(exception.message, exception.details));
2709
      }, this);
2710
2711
      messageHandler.on('DataLoaded', function transportPage(data) {
2712
        this.downloadInfoCapability.resolve(data);
2713
      }, this);
2714
2715
      messageHandler.on('PDFManagerReady', function transportPage(data) {
0 ignored issues
show
Unused Code introduced by
The parameter data is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2716
        if (this.pdfDataRangeTransport) {
2717
          this.pdfDataRangeTransport.transportReady();
2718
        }
2719
      }, this);
2720
2721
      messageHandler.on('StartRenderPage', function transportRender(data) {
2722
        var page = this.pageCache[data.pageIndex];
2723
2724
        page.stats.timeEnd('Page Request');
2725
        page._startRenderPage(data.transparency, data.intent);
2726
      }, this);
2727
2728
      messageHandler.on('RenderPageChunk', function transportRender(data) {
2729
        var page = this.pageCache[data.pageIndex];
2730
2731
        page._renderPageChunk(data.operatorList, data.intent);
2732
      }, this);
2733
2734
      messageHandler.on('commonobj', function transportObj(data) {
2735
        var id = data[0];
2736
        var type = data[1];
2737
        if (this.commonObjs.hasData(id)) {
2738
          return;
2739
        }
2740
2741
        switch (type) {
2742
          case 'Font':
2743
            var exportedData = data[2];
2744
2745
            var font;
2746
            if ('error' in exportedData) {
2747
              var error = exportedData.error;
2748
              warn('Error during font loading: ' + error);
2749
              this.commonObjs.resolve(id, error);
2750
              break;
2751
            } else {
2752
              font = new FontFaceObject(exportedData);
2753
            }
2754
2755
            FontLoader.bind(
2756
              [font],
2757
              function fontReady(fontObjs) {
0 ignored issues
show
Unused Code introduced by
The parameter fontObjs is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2758
                this.commonObjs.resolve(id, font);
2759
              }.bind(this)
2760
            );
2761
            break;
2762
          case 'FontPath':
2763
            this.commonObjs.resolve(id, data[2]);
2764
            break;
2765
          default:
2766
            error('Got unknown common object type ' + type);
2767
        }
2768
      }, this);
2769
2770
      messageHandler.on('obj', function transportObj(data) {
2771
        var id = data[0];
2772
        var pageIndex = data[1];
2773
        var type = data[2];
2774
        var pageProxy = this.pageCache[pageIndex];
2775
        var imageData;
2776
        if (pageProxy.objs.hasData(id)) {
2777
          return;
2778
        }
2779
2780
        switch (type) {
2781
          case 'JpegStream':
2782
            imageData = data[3];
2783
            loadJpegStream(id, imageData, pageProxy.objs);
2784
            break;
2785
          case 'Image':
2786
            imageData = data[3];
2787
            pageProxy.objs.resolve(id, imageData);
2788
2789
            // heuristics that will allow not to store large data
2790
            var MAX_IMAGE_SIZE_TO_STORE = 8000000;
2791
            if (imageData && 'data' in imageData &&
2792
                imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
2793
              pageProxy.cleanupAfterRender = true;
2794
            }
2795
            break;
2796
          default:
2797
            error('Got unknown object type ' + type);
2798
        }
2799
      }, this);
2800
2801
      messageHandler.on('DocProgress', function transportDocProgress(data) {
2802
        var loadingTask = this.loadingTask;
2803
        if (loadingTask.onProgress) {
2804
          loadingTask.onProgress({
2805
            loaded: data.loaded,
2806
            total: data.total
2807
          });
2808
        }
2809
      }, this);
2810
2811
      messageHandler.on('PageError', function transportError(data) {
2812
        var page = this.pageCache[data.pageNum - 1];
2813
        var intentState = page.intentStates[data.intent];
2814
        if (intentState.displayReadyCapability) {
2815
          intentState.displayReadyCapability.reject(data.error);
2816
        } else {
2817
          error(data.error);
2818
        }
2819
      }, this);
2820
2821
      messageHandler.on('JpegDecode', function(data) {
2822
        var imageUrl = data[0];
2823
        var components = data[1];
2824
        if (components !== 3 && components !== 1) {
2825
          return Promise.reject(
2826
            new Error('Only 3 components or 1 component can be returned'));
2827
        }
2828
2829
        return new Promise(function (resolve, reject) {
2830
          var img = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
2831
          img.onload = function () {
2832
            var width = img.width;
2833
            var height = img.height;
2834
            var size = width * height;
2835
            var rgbaLength = size * 4;
2836
            var buf = new Uint8Array(size * components);
2837
            var tmpCanvas = createScratchCanvas(width, height);
2838
            var tmpCtx = tmpCanvas.getContext('2d');
2839
            tmpCtx.drawImage(img, 0, 0);
2840
            var data = tmpCtx.getImageData(0, 0, width, height).data;
2841
            var i, j;
2842
2843
            if (components === 3) {
2844
              for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
2845
                buf[j] = data[i];
2846
                buf[j + 1] = data[i + 1];
2847
                buf[j + 2] = data[i + 2];
2848
              }
2849
            } else if (components === 1) {
2850
              for (i = 0, j = 0; i < rgbaLength; i += 4, j++) {
2851
                buf[j] = data[i];
2852
              }
2853
            }
2854
            resolve({ data: buf, width: width, height: height});
2855
          };
2856
          img.onerror = function () {
2857
            reject(new Error('JpegDecode failed to load image'));
2858
          };
2859
          img.src = imageUrl;
2860
        });
2861
      });
2862
    },
2863
2864
    fetchDocument: function WorkerTransport_fetchDocument(loadingTask, source) {
2865
      this.loadingTask = loadingTask;
2866
2867
      source.disableAutoFetch = PDFJS.disableAutoFetch;
2868
      source.disableStream = PDFJS.disableStream;
2869
      source.chunkedViewerLoading = !!this.pdfDataRangeTransport;
2870
      if (this.pdfDataRangeTransport) {
2871
        source.length = this.pdfDataRangeTransport.length;
2872
        source.initialData = this.pdfDataRangeTransport.initialData;
2873
      }
2874
      this.messageHandler.send('GetDocRequest', {
2875
        source: source,
2876
        disableRange: PDFJS.disableRange,
2877
        maxImageSize: PDFJS.maxImageSize,
2878
        cMapUrl: PDFJS.cMapUrl,
2879
        cMapPacked: PDFJS.cMapPacked,
2880
        disableFontFace: PDFJS.disableFontFace,
2881
        disableCreateObjectURL: PDFJS.disableCreateObjectURL,
2882
        verbosity: PDFJS.verbosity
2883
      });
2884
    },
2885
2886
    getData: function WorkerTransport_getData() {
2887
      return this.messageHandler.sendWithPromise('GetData', null);
2888
    },
2889
2890
    getPage: function WorkerTransport_getPage(pageNumber, capability) {
0 ignored issues
show
Unused Code introduced by
The parameter capability is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2891
      if (pageNumber <= 0 || pageNumber > this.numPages ||
2892
          (pageNumber|0) !== pageNumber) {
2893
        return Promise.reject(new Error('Invalid page request'));
2894
      }
2895
2896
      var pageIndex = pageNumber - 1;
2897
      if (pageIndex in this.pagePromises) {
2898
        return this.pagePromises[pageIndex];
2899
      }
2900
      var promise = this.messageHandler.sendWithPromise('GetPage', {
2901
        pageIndex: pageIndex
2902
      }).then(function (pageInfo) {
2903
        var page = new PDFPageProxy(pageIndex, pageInfo, this);
2904
        this.pageCache[pageIndex] = page;
2905
        return page;
2906
      }.bind(this));
2907
      this.pagePromises[pageIndex] = promise;
2908
      return promise;
2909
    },
2910
2911
    getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
2912
      return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref });
2913
    },
2914
2915
    getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
2916
      return this.messageHandler.sendWithPromise('GetAnnotations',
2917
        { pageIndex: pageIndex });
2918
    },
2919
2920
    getDestinations: function WorkerTransport_getDestinations() {
2921
      return this.messageHandler.sendWithPromise('GetDestinations', null);
2922
    },
2923
2924
    getDestination: function WorkerTransport_getDestination(id) {
2925
      return this.messageHandler.sendWithPromise('GetDestination', { id: id } );
2926
    },
2927
2928
    getAttachments: function WorkerTransport_getAttachments() {
2929
      return this.messageHandler.sendWithPromise('GetAttachments', null);
2930
    },
2931
2932
    getJavaScript: function WorkerTransport_getJavaScript() {
2933
      return this.messageHandler.sendWithPromise('GetJavaScript', null);
2934
    },
2935
2936
    getOutline: function WorkerTransport_getOutline() {
2937
      return this.messageHandler.sendWithPromise('GetOutline', null);
2938
    },
2939
2940
    getMetadata: function WorkerTransport_getMetadata() {
2941
      return this.messageHandler.sendWithPromise('GetMetadata', null).
2942
        then(function transportMetadata(results) {
2943
        return {
2944
          info: results[0],
2945
          metadata: (results[1] ? new PDFJS.Metadata(results[1]) : null)
2946
        };
2947
      });
2948
    },
2949
2950
    getStats: function WorkerTransport_getStats() {
2951
      return this.messageHandler.sendWithPromise('GetStats', null);
2952
    },
2953
2954
    startCleanup: function WorkerTransport_startCleanup() {
2955
      this.messageHandler.sendWithPromise('Cleanup', null).
2956
        then(function endCleanup() {
2957
        for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
2958
          var page = this.pageCache[i];
2959
          if (page) {
2960
            page.destroy();
2961
          }
2962
        }
2963
        this.commonObjs.clear();
2964
        FontLoader.clear();
2965
      }.bind(this));
2966
    }
2967
  };
2968
  return WorkerTransport;
2969
2970
})();
2971
2972
/**
2973
 * A PDF document and page is built of many objects. E.g. there are objects
2974
 * for fonts, images, rendering code and such. These objects might get processed
2975
 * inside of a worker. The `PDFObjects` implements some basic functions to
2976
 * manage these objects.
2977
 * @ignore
2978
 */
2979
var PDFObjects = (function PDFObjectsClosure() {
2980
  function PDFObjects() {
2981
    this.objs = {};
2982
  }
2983
2984
  PDFObjects.prototype = {
2985
    /**
2986
     * Internal function.
2987
     * Ensures there is an object defined for `objId`.
2988
     */
2989
    ensureObj: function PDFObjects_ensureObj(objId) {
2990
      if (this.objs[objId]) {
2991
        return this.objs[objId];
2992
      }
2993
2994
      var obj = {
2995
        capability: createPromiseCapability(),
2996
        data: null,
2997
        resolved: false
2998
      };
2999
      this.objs[objId] = obj;
3000
3001
      return obj;
3002
    },
3003
3004
    /**
3005
     * If called *without* callback, this returns the data of `objId` but the
3006
     * object needs to be resolved. If it isn't, this function throws.
3007
     *
3008
     * If called *with* a callback, the callback is called with the data of the
3009
     * object once the object is resolved. That means, if you call this
3010
     * function and the object is already resolved, the callback gets called
3011
     * right away.
3012
     */
3013
    get: function PDFObjects_get(objId, callback) {
3014
      // If there is a callback, then the get can be async and the object is
3015
      // not required to be resolved right now
3016
      if (callback) {
3017
        this.ensureObj(objId).capability.promise.then(callback);
3018
        return null;
3019
      }
3020
3021
      // If there isn't a callback, the user expects to get the resolved data
3022
      // directly.
3023
      var obj = this.objs[objId];
3024
3025
      // If there isn't an object yet or the object isn't resolved, then the
3026
      // data isn't ready yet!
3027
      if (!obj || !obj.resolved) {
3028
        error('Requesting object that isn\'t resolved yet ' + objId);
3029
      }
3030
3031
      return obj.data;
3032
    },
3033
3034
    /**
3035
     * Resolves the object `objId` with optional `data`.
3036
     */
3037
    resolve: function PDFObjects_resolve(objId, data) {
3038
      var obj = this.ensureObj(objId);
3039
3040
      obj.resolved = true;
3041
      obj.data = data;
3042
      obj.capability.resolve(data);
3043
    },
3044
3045
    isResolved: function PDFObjects_isResolved(objId) {
3046
      var objs = this.objs;
3047
3048
      if (!objs[objId]) {
3049
        return false;
3050
      } else {
3051
        return objs[objId].resolved;
3052
      }
3053
    },
3054
3055
    hasData: function PDFObjects_hasData(objId) {
3056
      return this.isResolved(objId);
3057
    },
3058
3059
    /**
3060
     * Returns the data of `objId` if object exists, null otherwise.
3061
     */
3062
    getData: function PDFObjects_getData(objId) {
3063
      var objs = this.objs;
3064
      if (!objs[objId] || !objs[objId].resolved) {
3065
        return null;
3066
      } else {
3067
        return objs[objId].data;
3068
      }
3069
    },
3070
3071
    clear: function PDFObjects_clear() {
3072
      this.objs = {};
3073
    }
3074
  };
3075
  return PDFObjects;
3076
})();
3077
3078
/**
3079
 * Allows controlling of the rendering tasks.
3080
 * @class
3081
 */
3082
var RenderTask = (function RenderTaskClosure() {
3083
  function RenderTask(internalRenderTask) {
3084
    this._internalRenderTask = internalRenderTask;
3085
3086
    /**
3087
     * Callback for incremental rendering -- a function that will be called
3088
     * each time the rendering is paused.  To continue rendering call the
3089
     * function that is the first argument to the callback.
3090
     * @type {function}
3091
     */
3092
    this.onContinue = null;
3093
  }
3094
3095
  RenderTask.prototype = /** @lends RenderTask.prototype */ {
3096
    /**
3097
     * Promise for rendering task completion.
3098
     * @return {Promise}
3099
     */
3100
    get promise() {
3101
      return this._internalRenderTask.capability.promise;
3102
    },
3103
3104
    /**
3105
     * Cancels the rendering task. If the task is currently rendering it will
3106
     * not be cancelled until graphics pauses with a timeout. The promise that
3107
     * this object extends will resolved when cancelled.
3108
     */
3109
    cancel: function RenderTask_cancel() {
3110
      this._internalRenderTask.cancel();
3111
    },
3112
3113
    /**
3114
     * Registers callbacks to indicate the rendering task completion.
3115
     *
3116
     * @param {function} onFulfilled The callback for the rendering completion.
3117
     * @param {function} onRejected The callback for the rendering failure.
3118
     * @return {Promise} A promise that is resolved after the onFulfilled or
3119
     *                   onRejected callback.
3120
     */
3121
    then: function RenderTask_then(onFulfilled, onRejected) {
0 ignored issues
show
Unused Code introduced by
The parameter onFulfilled is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter onRejected is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
3122
      return this.promise.then.apply(this.promise, arguments);
3123
    }
3124
  };
3125
3126
  return RenderTask;
3127
})();
3128
3129
/**
3130
 * For internal use only.
3131
 * @ignore
3132
 */
3133
var InternalRenderTask = (function InternalRenderTaskClosure() {
3134
3135
  function InternalRenderTask(callback, params, objs, commonObjs, operatorList,
3136
                              pageNumber) {
3137
    this.callback = callback;
3138
    this.params = params;
3139
    this.objs = objs;
3140
    this.commonObjs = commonObjs;
3141
    this.operatorListIdx = null;
3142
    this.operatorList = operatorList;
3143
    this.pageNumber = pageNumber;
3144
    this.running = false;
3145
    this.graphicsReadyCallback = null;
3146
    this.graphicsReady = false;
3147
    this.cancelled = false;
3148
    this.capability = createPromiseCapability();
3149
    this.task = new RenderTask(this);
3150
    // caching this-bound methods
3151
    this._continueBound = this._continue.bind(this);
3152
    this._scheduleNextBound = this._scheduleNext.bind(this);
3153
    this._nextBound = this._next.bind(this);
3154
  }
3155
3156
  InternalRenderTask.prototype = {
3157
3158
    initalizeGraphics:
3159
        function InternalRenderTask_initalizeGraphics(transparency) {
3160
3161
      if (this.cancelled) {
3162
        return;
3163
      }
3164
      if (PDFJS.pdfBug && 'StepperManager' in globalScope &&
3165
          globalScope.StepperManager.enabled) {
3166
        this.stepper = globalScope.StepperManager.create(this.pageNumber - 1);
3167
        this.stepper.init(this.operatorList);
3168
        this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
3169
      }
3170
3171
      var params = this.params;
3172
      this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
3173
                                    this.objs, params.imageLayer);
3174
3175
      this.gfx.beginDrawing(params.viewport, transparency);
3176
      this.operatorListIdx = 0;
3177
      this.graphicsReady = true;
3178
      if (this.graphicsReadyCallback) {
3179
        this.graphicsReadyCallback();
3180
      }
3181
    },
3182
3183
    cancel: function InternalRenderTask_cancel() {
3184
      this.running = false;
3185
      this.cancelled = true;
3186
      this.callback('cancelled');
3187
    },
3188
3189
    operatorListChanged: function InternalRenderTask_operatorListChanged() {
3190
      if (!this.graphicsReady) {
3191
        if (!this.graphicsReadyCallback) {
3192
          this.graphicsReadyCallback = this._continueBound;
3193
        }
3194
        return;
3195
      }
3196
3197
      if (this.stepper) {
3198
        this.stepper.updateOperatorList(this.operatorList);
3199
      }
3200
3201
      if (this.running) {
3202
        return;
3203
      }
3204
      this._continue();
3205
    },
3206
3207
    _continue: function InternalRenderTask__continue() {
3208
      this.running = true;
3209
      if (this.cancelled) {
3210
        return;
3211
      }
3212
      if (this.task.onContinue) {
3213
        this.task.onContinue.call(this.task, this._scheduleNextBound);
3214
      } else {
3215
        this._scheduleNext();
3216
      }
3217
    },
3218
3219
    _scheduleNext: function InternalRenderTask__scheduleNext() {
3220
      window.requestAnimationFrame(this._nextBound);
3221
    },
3222
3223
    _next: function InternalRenderTask__next() {
3224
      if (this.cancelled) {
3225
        return;
3226
      }
3227
      this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList,
3228
                                        this.operatorListIdx,
3229
                                        this._continueBound,
3230
                                        this.stepper);
3231
      if (this.operatorListIdx === this.operatorList.argsArray.length) {
3232
        this.running = false;
3233
        if (this.operatorList.lastChunk) {
3234
          this.gfx.endDrawing();
3235
          this.callback();
3236
        }
3237
      }
3238
    }
3239
3240
  };
3241
3242
  return InternalRenderTask;
3243
})();
3244
3245
3246
var Metadata = PDFJS.Metadata = (function MetadataClosure() {
3247
  function fixMetadata(meta) {
3248
    return meta.replace(/>\\376\\377([^<]+)/g, function(all, codes) {
3249
      var bytes = codes.replace(/\\([0-3])([0-7])([0-7])/g,
3250
                                function(code, d1, d2, d3) {
3251
        return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
3252
      });
3253
      var chars = '';
3254
      for (var i = 0; i < bytes.length; i += 2) {
3255
        var code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
3256
        chars += code >= 32 && code < 127 && code !== 60 && code !== 62 &&
3257
          code !== 38 && false ? String.fromCharCode(code) :
3258
          '&#x' + (0x10000 + code).toString(16).substring(1) + ';';
3259
      }
3260
      return '>' + chars;
3261
    });
3262
  }
3263
3264
  function Metadata(meta) {
3265
    if (typeof meta === 'string') {
3266
      // Ghostscript produces invalid metadata
3267
      meta = fixMetadata(meta);
3268
3269
      var parser = new DOMParser();
0 ignored issues
show
Bug introduced by
The variable DOMParser seems to be never declared. If this is a global, consider adding a /** global: DOMParser */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3270
      meta = parser.parseFromString(meta, 'application/xml');
3271
    } else if (!(meta instanceof Document)) {
0 ignored issues
show
Bug introduced by
The variable Document seems to be never declared. If this is a global, consider adding a /** global: Document */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3272
      error('Metadata: Invalid metadata object');
3273
    }
3274
3275
    this.metaDocument = meta;
3276
    this.metadata = {};
3277
    this.parse();
3278
  }
3279
3280
  Metadata.prototype = {
3281
    parse: function Metadata_parse() {
3282
      var doc = this.metaDocument;
3283
      var rdf = doc.documentElement;
3284
3285
      if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in <xmpmeta>
3286
        rdf = rdf.firstChild;
3287
        while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') {
3288
          rdf = rdf.nextSibling;
3289
        }
3290
      }
3291
3292
      var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
3293
      if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) {
3294
        return;
3295
      }
3296
3297
      var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength;
3298
      for (i = 0, length = children.length; i < length; i++) {
3299
        desc = children[i];
3300
        if (desc.nodeName.toLowerCase() !== 'rdf:description') {
3301
          continue;
3302
        }
3303
3304
        for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
3305
          if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {
3306
            entry = desc.childNodes[ii];
3307
            name = entry.nodeName.toLowerCase();
3308
            this.metadata[name] = entry.textContent.trim();
3309
          }
3310
        }
3311
      }
3312
    },
3313
3314
    get: function Metadata_get(name) {
3315
      return this.metadata[name] || null;
3316
    },
3317
3318
    has: function Metadata_has(name) {
3319
      return typeof this.metadata[name] !== 'undefined';
3320
    }
3321
  };
3322
3323
  return Metadata;
3324
})();
3325
3326
3327
// <canvas> contexts store most of the state we need natively.
3328
// However, PDF needs a bit more state, which we store here.
3329
3330
// Minimal font size that would be used during canvas fillText operations.
3331
var MIN_FONT_SIZE = 16;
3332
// Maximum font size that would be used during canvas fillText operations.
3333
var MAX_FONT_SIZE = 100;
3334
var MAX_GROUP_SIZE = 4096;
3335
3336
// Heuristic value used when enforcing minimum line widths.
3337
var MIN_WIDTH_FACTOR = 0.65;
3338
3339
var COMPILE_TYPE3_GLYPHS = true;
3340
var MAX_SIZE_TO_COMPILE = 1000;
3341
3342
var FULL_CHUNK_HEIGHT = 16;
3343
3344
function createScratchCanvas(width, height) {
3345
  var canvas = document.createElement('canvas');
3346
  canvas.width = width;
3347
  canvas.height = height;
3348
  return canvas;
3349
}
3350
3351
function addContextCurrentTransform(ctx) {
3352
  // If the context doesn't expose a `mozCurrentTransform`, add a JS based one.
3353
  if (!ctx.mozCurrentTransform) {
3354
    ctx._originalSave = ctx.save;
3355
    ctx._originalRestore = ctx.restore;
3356
    ctx._originalRotate = ctx.rotate;
3357
    ctx._originalScale = ctx.scale;
3358
    ctx._originalTranslate = ctx.translate;
3359
    ctx._originalTransform = ctx.transform;
3360
    ctx._originalSetTransform = ctx.setTransform;
3361
3362
    ctx._transformMatrix = ctx._transformMatrix || [1, 0, 0, 1, 0, 0];
3363
    ctx._transformStack = [];
3364
3365
    Object.defineProperty(ctx, 'mozCurrentTransform', {
3366
      get: function getCurrentTransform() {
3367
        return this._transformMatrix;
3368
      }
3369
    });
3370
3371
    Object.defineProperty(ctx, 'mozCurrentTransformInverse', {
3372
      get: function getCurrentTransformInverse() {
3373
        // Calculation done using WolframAlpha:
3374
        // http://www.wolframalpha.com/input/?
3375
        //   i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}}
3376
3377
        var m = this._transformMatrix;
3378
        var a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];
3379
3380
        var ad_bc = a * d - b * c;
3381
        var bc_ad = b * c - a * d;
3382
3383
        return [
3384
          d / ad_bc,
3385
          b / bc_ad,
3386
          c / bc_ad,
3387
          a / ad_bc,
3388
          (d * e - c * f) / bc_ad,
3389
          (b * e - a * f) / ad_bc
3390
        ];
3391
      }
3392
    });
3393
3394
    ctx.save = function ctxSave() {
3395
      var old = this._transformMatrix;
3396
      this._transformStack.push(old);
3397
      this._transformMatrix = old.slice(0, 6);
3398
3399
      this._originalSave();
3400
    };
3401
3402
    ctx.restore = function ctxRestore() {
3403
      var prev = this._transformStack.pop();
3404
      if (prev) {
3405
        this._transformMatrix = prev;
3406
        this._originalRestore();
3407
      }
3408
    };
3409
3410
    ctx.translate = function ctxTranslate(x, y) {
3411
      var m = this._transformMatrix;
3412
      m[4] = m[0] * x + m[2] * y + m[4];
3413
      m[5] = m[1] * x + m[3] * y + m[5];
3414
3415
      this._originalTranslate(x, y);
3416
    };
3417
3418
    ctx.scale = function ctxScale(x, y) {
3419
      var m = this._transformMatrix;
3420
      m[0] = m[0] * x;
3421
      m[1] = m[1] * x;
3422
      m[2] = m[2] * y;
3423
      m[3] = m[3] * y;
3424
3425
      this._originalScale(x, y);
3426
    };
3427
3428
    ctx.transform = function ctxTransform(a, b, c, d, e, f) {
3429
      var m = this._transformMatrix;
3430
      this._transformMatrix = [
3431
        m[0] * a + m[2] * b,
3432
        m[1] * a + m[3] * b,
3433
        m[0] * c + m[2] * d,
3434
        m[1] * c + m[3] * d,
3435
        m[0] * e + m[2] * f + m[4],
3436
        m[1] * e + m[3] * f + m[5]
3437
      ];
3438
3439
      ctx._originalTransform(a, b, c, d, e, f);
3440
    };
3441
3442
    ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {
3443
      this._transformMatrix = [a, b, c, d, e, f];
3444
3445
      ctx._originalSetTransform(a, b, c, d, e, f);
3446
    };
3447
3448
    ctx.rotate = function ctxRotate(angle) {
3449
      var cosValue = Math.cos(angle);
3450
      var sinValue = Math.sin(angle);
3451
3452
      var m = this._transformMatrix;
3453
      this._transformMatrix = [
3454
        m[0] * cosValue + m[2] * sinValue,
3455
        m[1] * cosValue + m[3] * sinValue,
3456
        m[0] * (-sinValue) + m[2] * cosValue,
3457
        m[1] * (-sinValue) + m[3] * cosValue,
3458
        m[4],
3459
        m[5]
3460
      ];
3461
3462
      this._originalRotate(angle);
3463
    };
3464
  }
3465
}
3466
3467
var CachedCanvases = (function CachedCanvasesClosure() {
3468
  var cache = {};
3469
  return {
3470
    getCanvas: function CachedCanvases_getCanvas(id, width, height,
3471
                                                 trackTransform) {
3472
      var canvasEntry;
3473
      if (cache[id] !== undefined) {
3474
        canvasEntry = cache[id];
3475
        canvasEntry.canvas.width = width;
3476
        canvasEntry.canvas.height = height;
3477
        // reset canvas transform for emulated mozCurrentTransform, if needed
3478
        canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);
3479
      } else {
3480
        var canvas = createScratchCanvas(width, height);
3481
        var ctx = canvas.getContext('2d');
3482
        if (trackTransform) {
3483
          addContextCurrentTransform(ctx);
3484
        }
3485
        cache[id] = canvasEntry = {canvas: canvas, context: ctx};
3486
      }
3487
      return canvasEntry;
3488
    },
3489
    clear: function () {
3490
      for (var id in cache) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
3491
        var canvasEntry = cache[id];
3492
        // Zeroing the width and height causes Firefox to release graphics
3493
        // resources immediately, which can greatly reduce memory consumption.
3494
        canvasEntry.canvas.width = 0;
3495
        canvasEntry.canvas.height = 0;
3496
        delete cache[id];
3497
      }
3498
    }
3499
  };
3500
})();
3501
3502
function compileType3Glyph(imgData) {
3503
  var POINT_TO_PROCESS_LIMIT = 1000;
3504
3505
  var width = imgData.width, height = imgData.height;
3506
  var i, j, j0, width1 = width + 1;
3507
  var points = new Uint8Array(width1 * (height + 1));
3508
  var POINT_TYPES =
3509
      new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
3510
3511
  // decodes bit-packed mask data
3512
  var lineSize = (width + 7) & ~7, data0 = imgData.data;
3513
  var data = new Uint8Array(lineSize * height), pos = 0, ii;
3514
  for (i = 0, ii = data0.length; i < ii; i++) {
3515
    var mask = 128, elem = data0[i];
3516
    while (mask > 0) {
3517
      data[pos++] = (elem & mask) ? 0 : 255;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3518
      mask >>= 1;
3519
    }
3520
  }
3521
3522
  // finding iteresting points: every point is located between mask pixels,
3523
  // so there will be points of the (width + 1)x(height + 1) grid. Every point
3524
  // will have flags assigned based on neighboring mask pixels:
3525
  //   4 | 8
3526
  //   --P--
3527
  //   2 | 1
3528
  // We are interested only in points with the flags:
3529
  //   - outside corners: 1, 2, 4, 8;
3530
  //   - inside corners: 7, 11, 13, 14;
3531
  //   - and, intersections: 5, 10.
3532
  var count = 0;
3533
  pos = 0;
3534
  if (data[pos] !== 0) {
3535
    points[0] = 1;
3536
    ++count;
3537
  }
3538
  for (j = 1; j < width; j++) {
3539
    if (data[pos] !== data[pos + 1]) {
3540
      points[j] = data[pos] ? 2 : 1;
3541
      ++count;
3542
    }
3543
    pos++;
3544
  }
3545
  if (data[pos] !== 0) {
3546
    points[j] = 2;
3547
    ++count;
3548
  }
3549
  for (i = 1; i < height; i++) {
3550
    pos = i * lineSize;
3551
    j0 = i * width1;
3552
    if (data[pos - lineSize] !== data[pos]) {
3553
      points[j0] = data[pos] ? 1 : 8;
3554
      ++count;
3555
    }
3556
    // 'sum' is the position of the current pixel configuration in the 'TYPES'
3557
    // array (in order 8-1-2-4, so we can use '>>2' to shift the column).
3558
    var sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);
3559
    for (j = 1; j < width; j++) {
3560
      sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) +
3561
            (data[pos - lineSize + 1] ? 8 : 0);
3562
      if (POINT_TYPES[sum]) {
3563
        points[j0 + j] = POINT_TYPES[sum];
3564
        ++count;
3565
      }
3566
      pos++;
3567
    }
3568
    if (data[pos - lineSize] !== data[pos]) {
3569
      points[j0 + j] = data[pos] ? 2 : 4;
3570
      ++count;
3571
    }
3572
3573
    if (count > POINT_TO_PROCESS_LIMIT) {
3574
      return null;
3575
    }
3576
  }
3577
3578
  pos = lineSize * (height - 1);
3579
  j0 = i * width1;
3580
  if (data[pos] !== 0) {
3581
    points[j0] = 8;
3582
    ++count;
3583
  }
3584
  for (j = 1; j < width; j++) {
3585
    if (data[pos] !== data[pos + 1]) {
3586
      points[j0 + j] = data[pos] ? 4 : 8;
3587
      ++count;
3588
    }
3589
    pos++;
3590
  }
3591
  if (data[pos] !== 0) {
3592
    points[j0 + j] = 4;
3593
    ++count;
3594
  }
3595
  if (count > POINT_TO_PROCESS_LIMIT) {
3596
    return null;
3597
  }
3598
3599
  // building outlines
3600
  var steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);
3601
  var outlines = [];
3602
  for (i = 0; count && i <= height; i++) {
3603
    var p = i * width1;
3604
    var end = p + width;
3605
    while (p < end && !points[p]) {
3606
      p++;
3607
    }
3608
    if (p === end) {
3609
      continue;
3610
    }
3611
    var coords = [p % width1, i];
3612
3613
    var type = points[p], p0 = p, pp;
3614
    do {
3615
      var step = steps[type];
3616
      do {
3617
        p += step;
3618
      } while (!points[p]);
3619
3620
      pp = points[p];
3621
      if (pp !== 5 && pp !== 10) {
3622
        // set new direction
3623
        type = pp;
3624
        // delete mark
3625
        points[p] = 0;
3626
      } else { // type is 5 or 10, ie, a crossing
3627
        // set new direction
3628
        type = pp & ((0x33 * type) >> 4);
3629
        // set new type for "future hit"
3630
        points[p] &= (type >> 2 | type << 2);
3631
      }
3632
3633
      coords.push(p % width1);
3634
      coords.push((p / width1) | 0);
3635
      --count;
3636
    } while (p0 !== p);
3637
    outlines.push(coords);
3638
    --i;
3639
  }
3640
3641
  var drawOutline = function(c) {
3642
    c.save();
3643
    // the path shall be painted in [0..1]x[0..1] space
3644
    c.scale(1 / width, -1 / height);
3645
    c.translate(0, -height);
3646
    c.beginPath();
3647
    for (var i = 0, ii = outlines.length; i < ii; i++) {
3648
      var o = outlines[i];
3649
      c.moveTo(o[0], o[1]);
3650
      for (var j = 2, jj = o.length; j < jj; j += 2) {
3651
        c.lineTo(o[j], o[j+1]);
3652
      }
3653
    }
3654
    c.fill();
3655
    c.beginPath();
3656
    c.restore();
3657
  };
3658
3659
  return drawOutline;
3660
}
3661
3662
var CanvasExtraState = (function CanvasExtraStateClosure() {
3663
  function CanvasExtraState(old) {
3664
    // Are soft masks and alpha values shapes or opacities?
3665
    this.alphaIsShape = false;
3666
    this.fontSize = 0;
3667
    this.fontSizeScale = 1;
3668
    this.textMatrix = IDENTITY_MATRIX;
3669
    this.textMatrixScale = 1;
3670
    this.fontMatrix = FONT_IDENTITY_MATRIX;
3671
    this.leading = 0;
3672
    // Current point (in user coordinates)
3673
    this.x = 0;
3674
    this.y = 0;
3675
    // Start of text line (in text coordinates)
3676
    this.lineX = 0;
3677
    this.lineY = 0;
3678
    // Character and word spacing
3679
    this.charSpacing = 0;
3680
    this.wordSpacing = 0;
3681
    this.textHScale = 1;
3682
    this.textRenderingMode = TextRenderingMode.FILL;
3683
    this.textRise = 0;
3684
    // Default fore and background colors
3685
    this.fillColor = '#000000';
3686
    this.strokeColor = '#000000';
3687
    this.patternFill = false;
3688
    // Note: fill alpha applies to all non-stroking operations
3689
    this.fillAlpha = 1;
3690
    this.strokeAlpha = 1;
3691
    this.lineWidth = 1;
3692
    this.activeSMask = null; // nonclonable field (see the save method below)
3693
3694
    this.old = old;
3695
  }
3696
3697
  CanvasExtraState.prototype = {
3698
    clone: function CanvasExtraState_clone() {
3699
      return Object.create(this);
3700
    },
3701
    setCurrentPoint: function CanvasExtraState_setCurrentPoint(x, y) {
3702
      this.x = x;
3703
      this.y = y;
3704
    }
3705
  };
3706
  return CanvasExtraState;
3707
})();
3708
3709
var CanvasGraphics = (function CanvasGraphicsClosure() {
3710
  // Defines the time the executeOperatorList is going to be executing
3711
  // before it stops and shedules a continue of execution.
3712
  var EXECUTION_TIME = 15;
3713
  // Defines the number of steps before checking the execution time
3714
  var EXECUTION_STEPS = 10;
3715
3716
  function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) {
3717
    this.ctx = canvasCtx;
3718
    this.current = new CanvasExtraState();
3719
    this.stateStack = [];
3720
    this.pendingClip = null;
3721
    this.pendingEOFill = false;
3722
    this.res = null;
3723
    this.xobjs = null;
3724
    this.commonObjs = commonObjs;
3725
    this.objs = objs;
3726
    this.imageLayer = imageLayer;
3727
    this.groupStack = [];
3728
    this.processingType3 = null;
3729
    // Patterns are painted relative to the initial page/form transform, see pdf
3730
    // spec 8.7.2 NOTE 1.
3731
    this.baseTransform = null;
3732
    this.baseTransformStack = [];
3733
    this.groupLevel = 0;
3734
    this.smaskStack = [];
3735
    this.smaskCounter = 0;
3736
    this.tempSMask = null;
3737
    if (canvasCtx) {
3738
      // NOTE: if mozCurrentTransform is polyfilled, then the current state of
3739
      // the transformation must already be set in canvasCtx._transformMatrix.
3740
      addContextCurrentTransform(canvasCtx);
3741
    }
3742
    this.cachedGetSinglePixelWidth = null;
3743
  }
3744
3745
  function putBinaryImageData(ctx, imgData) {
3746
    if (typeof ImageData !== 'undefined' && imgData instanceof ImageData) {
0 ignored issues
show
Bug introduced by
The variable ImageData seems to be never declared. If this is a global, consider adding a /** global: ImageData */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3747
      ctx.putImageData(imgData, 0, 0);
3748
      return;
3749
    }
3750
3751
    // Put the image data to the canvas in chunks, rather than putting the
3752
    // whole image at once.  This saves JS memory, because the ImageData object
3753
    // is smaller. It also possibly saves C++ memory within the implementation
3754
    // of putImageData(). (E.g. in Firefox we make two short-lived copies of
3755
    // the data passed to putImageData()). |n| shouldn't be too small, however,
3756
    // because too many putImageData() calls will slow things down.
3757
    //
3758
    // Note: as written, if the last chunk is partial, the putImageData() call
3759
    // will (conceptually) put pixels past the bounds of the canvas.  But
3760
    // that's ok; any such pixels are ignored.
3761
3762
    var height = imgData.height, width = imgData.width;
3763
    var partialChunkHeight = height % FULL_CHUNK_HEIGHT;
3764
    var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
3765
    var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
3766
3767
    var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
3768
    var srcPos = 0, destPos;
3769
    var src = imgData.data;
3770
    var dest = chunkImgData.data;
3771
    var i, j, thisChunkHeight, elemsInThisChunk;
3772
3773
    // There are multiple forms in which the pixel data can be passed, and
3774
    // imgData.kind tells us which one this is.
3775
    if (imgData.kind === ImageKind.GRAYSCALE_1BPP) {
3776
      // Grayscale, 1 bit per pixel (i.e. black-and-white).
3777
      var srcLength = src.byteLength;
3778
      var dest32 = PDFJS.hasCanvasTypedArrays ? new Uint32Array(dest.buffer) :
3779
        new Uint32ArrayView(dest);
3780
      var dest32DataLength = dest32.length;
3781
      var fullSrcDiff = (width + 7) >> 3;
3782
      var white = 0xFFFFFFFF;
3783
      var black = (PDFJS.isLittleEndian || !PDFJS.hasCanvasTypedArrays) ?
3784
        0xFF000000 : 0x000000FF;
3785
      for (i = 0; i < totalChunks; i++) {
3786
        thisChunkHeight =
3787
          (i < fullChunks) ? FULL_CHUNK_HEIGHT : partialChunkHeight;
3788
        destPos = 0;
3789
        for (j = 0; j < thisChunkHeight; j++) {
3790
          var srcDiff = srcLength - srcPos;
3791
          var k = 0;
3792
          var kEnd = (srcDiff > fullSrcDiff) ? width : srcDiff * 8 - 7;
3793
          var kEndUnrolled = kEnd & ~7;
3794
          var mask = 0;
3795
          var srcByte = 0;
3796
          for (; k < kEndUnrolled; k += 8) {
3797
            srcByte = src[srcPos++];
3798
            dest32[destPos++] = (srcByte & 128) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3799
            dest32[destPos++] = (srcByte & 64) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3800
            dest32[destPos++] = (srcByte & 32) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3801
            dest32[destPos++] = (srcByte & 16) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3802
            dest32[destPos++] = (srcByte & 8) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3803
            dest32[destPos++] = (srcByte & 4) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3804
            dest32[destPos++] = (srcByte & 2) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3805
            dest32[destPos++] = (srcByte & 1) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3806
          }
3807
          for (; k < kEnd; k++) {
3808
             if (mask === 0) {
3809
               srcByte = src[srcPos++];
3810
               mask = 128;
3811
             }
3812
3813
            dest32[destPos++] = (srcByte & mask) ? white : black;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3814
            mask >>= 1;
3815
          }
3816
        }
3817
        // We ran out of input. Make all remaining pixels transparent.
3818
        while (destPos < dest32DataLength) {
3819
          dest32[destPos++] = 0;
3820
        }
3821
3822
        ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
3823
      }
3824
    } else if (imgData.kind === ImageKind.RGBA_32BPP) {
3825
      // RGBA, 32-bits per pixel.
3826
3827
      j = 0;
3828
      elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;
3829
      for (i = 0; i < fullChunks; i++) {
3830
        dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
3831
        srcPos += elemsInThisChunk;
3832
3833
        ctx.putImageData(chunkImgData, 0, j);
3834
        j += FULL_CHUNK_HEIGHT;
3835
      }
3836
      if (i < totalChunks) {
3837
        elemsInThisChunk = width * partialChunkHeight * 4;
3838
        dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
3839
        ctx.putImageData(chunkImgData, 0, j);
3840
      }
3841
3842
    } else if (imgData.kind === ImageKind.RGB_24BPP) {
3843
      // RGB, 24-bits per pixel.
3844
      thisChunkHeight = FULL_CHUNK_HEIGHT;
3845
      elemsInThisChunk = width * thisChunkHeight;
3846
      for (i = 0; i < totalChunks; i++) {
3847
        if (i >= fullChunks) {
3848
          thisChunkHeight = partialChunkHeight;
3849
          elemsInThisChunk = width * thisChunkHeight;
3850
        }
3851
3852
        destPos = 0;
3853
        for (j = elemsInThisChunk; j--;) {
3854
          dest[destPos++] = src[srcPos++];
3855
          dest[destPos++] = src[srcPos++];
3856
          dest[destPos++] = src[srcPos++];
3857
          dest[destPos++] = 255;
3858
        }
3859
        ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
3860
      }
3861
    } else {
3862
      error('bad image kind: ' + imgData.kind);
3863
    }
3864
  }
3865
3866
  function putBinaryImageMask(ctx, imgData) {
3867
    var height = imgData.height, width = imgData.width;
3868
    var partialChunkHeight = height % FULL_CHUNK_HEIGHT;
3869
    var fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
3870
    var totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
3871
3872
    var chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
3873
    var srcPos = 0;
3874
    var src = imgData.data;
3875
    var dest = chunkImgData.data;
3876
3877
    for (var i = 0; i < totalChunks; i++) {
3878
      var thisChunkHeight =
3879
        (i < fullChunks) ? FULL_CHUNK_HEIGHT : partialChunkHeight;
3880
3881
      // Expand the mask so it can be used by the canvas.  Any required
3882
      // inversion has already been handled.
3883
      var destPos = 3; // alpha component offset
3884
      for (var j = 0; j < thisChunkHeight; j++) {
3885
        var mask = 0;
3886
        for (var k = 0; k < width; k++) {
3887
          if (!mask) {
3888
            var elem = src[srcPos++];
3889
            mask = 128;
3890
          }
3891
          dest[destPos] = (elem & mask) ? 0 : 255;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
Bug introduced by
The variable elem seems to not be initialized for all possible execution paths.
Loading history...
3892
          destPos += 4;
3893
          mask >>= 1;
3894
        }
3895
      }
3896
      ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
3897
    }
3898
  }
3899
3900
  function copyCtxState(sourceCtx, destCtx) {
3901
    var properties = ['strokeStyle', 'fillStyle', 'fillRule', 'globalAlpha',
3902
                      'lineWidth', 'lineCap', 'lineJoin', 'miterLimit',
3903
                      'globalCompositeOperation', 'font'];
3904
    for (var i = 0, ii = properties.length; i < ii; i++) {
3905
      var property = properties[i];
3906
      if (sourceCtx[property] !== undefined) {
3907
        destCtx[property] = sourceCtx[property];
3908
      }
3909
    }
3910
    if (sourceCtx.setLineDash !== undefined) {
3911
      destCtx.setLineDash(sourceCtx.getLineDash());
3912
      destCtx.lineDashOffset =  sourceCtx.lineDashOffset;
3913
    } else if (sourceCtx.mozDashOffset !== undefined) {
3914
      destCtx.mozDash = sourceCtx.mozDash;
3915
      destCtx.mozDashOffset = sourceCtx.mozDashOffset;
3916
    }
3917
  }
3918
3919
  function composeSMaskBackdrop(bytes, r0, g0, b0) {
3920
    var length = bytes.length;
3921
    for (var i = 3; i < length; i += 4) {
3922
      var alpha = bytes[i];
3923
      if (alpha === 0) {
3924
        bytes[i - 3] = r0;
3925
        bytes[i - 2] = g0;
3926
        bytes[i - 1] = b0;
3927
      } else if (alpha < 255) {
3928
        var alpha_ = 255 - alpha;
3929
        bytes[i - 3] = (bytes[i - 3] * alpha + r0 * alpha_) >> 8;
3930
        bytes[i - 2] = (bytes[i - 2] * alpha + g0 * alpha_) >> 8;
3931
        bytes[i - 1] = (bytes[i - 1] * alpha + b0 * alpha_) >> 8;
3932
      }
3933
    }
3934
  }
3935
3936
  function composeSMaskAlpha(maskData, layerData) {
3937
    var length = maskData.length;
3938
    var scale = 1 / 255;
3939
    for (var i = 3; i < length; i += 4) {
3940
      var alpha = maskData[i];
3941
      layerData[i] = (layerData[i] * alpha * scale) | 0;
3942
    }
3943
  }
3944
3945
  function composeSMaskLuminosity(maskData, layerData) {
3946
    var length = maskData.length;
3947
    for (var i = 3; i < length; i += 4) {
3948
      var y = (maskData[i - 3] * 77) +  // * 0.3 / 255 * 0x10000
3949
              (maskData[i - 2] * 152) + // * 0.59 ....
3950
              (maskData[i - 1] * 28);   // * 0.11 ....
3951
      layerData[i] = (layerData[i] * y) >> 16;
3952
    }
3953
  }
3954
3955
  function genericComposeSMask(maskCtx, layerCtx, width, height,
3956
                               subtype, backdrop) {
3957
    var hasBackdrop = !!backdrop;
3958
    var r0 = hasBackdrop ? backdrop[0] : 0;
3959
    var g0 = hasBackdrop ? backdrop[1] : 0;
3960
    var b0 = hasBackdrop ? backdrop[2] : 0;
3961
3962
    var composeFn;
3963
    if (subtype === 'Luminosity') {
3964
      composeFn = composeSMaskLuminosity;
3965
    } else {
3966
      composeFn = composeSMaskAlpha;
3967
    }
3968
3969
    // processing image in chunks to save memory
3970
    var PIXELS_TO_PROCESS = 1048576;
3971
    var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
3972
    for (var row = 0; row < height; row += chunkSize) {
3973
      var chunkHeight = Math.min(chunkSize, height - row);
3974
      var maskData = maskCtx.getImageData(0, row, width, chunkHeight);
3975
      var layerData = layerCtx.getImageData(0, row, width, chunkHeight);
3976
3977
      if (hasBackdrop) {
3978
        composeSMaskBackdrop(maskData.data, r0, g0, b0);
3979
      }
3980
      composeFn(maskData.data, layerData.data);
3981
3982
      maskCtx.putImageData(layerData, 0, row);
3983
    }
3984
  }
3985
3986
  function composeSMask(ctx, smask, layerCtx) {
3987
    var mask = smask.canvas;
3988
    var maskCtx = smask.context;
3989
3990
    ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY,
3991
                     smask.offsetX, smask.offsetY);
3992
3993
    var backdrop = smask.backdrop || null;
3994
    if (WebGLUtils.isEnabled) {
3995
      var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask,
3996
        {subtype: smask.subtype, backdrop: backdrop});
3997
      ctx.setTransform(1, 0, 0, 1, 0, 0);
3998
      ctx.drawImage(composed, smask.offsetX, smask.offsetY);
3999
      return;
4000
    }
4001
    genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height,
4002
                        smask.subtype, backdrop);
4003
    ctx.drawImage(mask, 0, 0);
4004
  }
4005
4006
  var LINE_CAP_STYLES = ['butt', 'round', 'square'];
4007
  var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
4008
  var NORMAL_CLIP = {};
4009
  var EO_CLIP = {};
4010
4011
  CanvasGraphics.prototype = {
4012
4013
    beginDrawing: function CanvasGraphics_beginDrawing(viewport, transparency) {
4014
      // For pdfs that use blend modes we have to clear the canvas else certain
4015
      // blend modes can look wrong since we'd be blending with a white
4016
      // backdrop. The problem with a transparent backdrop though is we then
4017
      // don't get sub pixel anti aliasing on text, so we fill with white if
4018
      // we can.
4019
      var width = this.ctx.canvas.width;
4020
      var height = this.ctx.canvas.height;
4021
      if (transparency) {
4022
        this.ctx.clearRect(0, 0, width, height);
4023
      } else {
4024
        this.ctx.mozOpaque = true;
4025
        this.ctx.save();
4026
        this.ctx.fillStyle = 'rgb(255, 255, 255)';
4027
        this.ctx.fillRect(0, 0, width, height);
4028
        this.ctx.restore();
4029
      }
4030
4031
      var transform = viewport.transform;
4032
4033
      this.ctx.save();
4034
      this.ctx.transform.apply(this.ctx, transform);
4035
4036
      this.baseTransform = this.ctx.mozCurrentTransform.slice();
4037
4038
      if (this.imageLayer) {
4039
        this.imageLayer.beginLayout();
4040
      }
4041
    },
4042
4043
    executeOperatorList: function CanvasGraphics_executeOperatorList(
4044
                                    operatorList,
4045
                                    executionStartIdx, continueCallback,
4046
                                    stepper) {
4047
      var argsArray = operatorList.argsArray;
4048
      var fnArray = operatorList.fnArray;
4049
      var i = executionStartIdx || 0;
4050
      var argsArrayLen = argsArray.length;
4051
4052
      // Sometimes the OperatorList to execute is empty.
4053
      if (argsArrayLen === i) {
4054
        return i;
4055
      }
4056
4057
      var chunkOperations = (argsArrayLen - i > EXECUTION_STEPS &&
4058
                             typeof continueCallback === 'function');
4059
      var endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
4060
      var steps = 0;
4061
4062
      var commonObjs = this.commonObjs;
4063
      var objs = this.objs;
4064
      var fnId;
4065
4066
      while (true) {
4067
        if (stepper !== undefined && i === stepper.nextBreakPoint) {
4068
          stepper.breakIt(i, continueCallback);
4069
          return i;
4070
        }
4071
4072
        fnId = fnArray[i];
4073
4074
        if (fnId !== OPS.dependency) {
4075
          this[fnId].apply(this, argsArray[i]);
4076
        } else {
4077
          var deps = argsArray[i];
4078
          for (var n = 0, nn = deps.length; n < nn; n++) {
4079
            var depObjId = deps[n];
4080
            var common = depObjId[0] === 'g' && depObjId[1] === '_';
4081
            var objsPool = common ? commonObjs : objs;
4082
4083
            // If the promise isn't resolved yet, add the continueCallback
4084
            // to the promise and bail out.
4085
            if (!objsPool.isResolved(depObjId)) {
4086
              objsPool.get(depObjId, continueCallback);
4087
              return i;
4088
            }
4089
          }
4090
        }
4091
4092
        i++;
4093
4094
        // If the entire operatorList was executed, stop as were done.
4095
        if (i === argsArrayLen) {
4096
          return i;
4097
        }
4098
4099
        // If the execution took longer then a certain amount of time and
4100
        // `continueCallback` is specified, interrupt the execution.
4101
        if (chunkOperations && ++steps > EXECUTION_STEPS) {
4102
          if (Date.now() > endTime) {
4103
            continueCallback();
4104
            return i;
4105
          }
4106
          steps = 0;
4107
        }
4108
4109
        // If the operatorList isn't executed completely yet OR the execution
4110
        // time was short enough, do another execution round.
4111
      }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
4112
    },
4113
4114
    endDrawing: function CanvasGraphics_endDrawing() {
4115
      this.ctx.restore();
4116
      CachedCanvases.clear();
4117
      WebGLUtils.clear();
4118
4119
      if (this.imageLayer) {
4120
        this.imageLayer.endLayout();
4121
      }
4122
    },
4123
4124
    // Graphics state
4125
    setLineWidth: function CanvasGraphics_setLineWidth(width) {
4126
      this.current.lineWidth = width;
4127
      this.ctx.lineWidth = width;
4128
    },
4129
    setLineCap: function CanvasGraphics_setLineCap(style) {
4130
      this.ctx.lineCap = LINE_CAP_STYLES[style];
4131
    },
4132
    setLineJoin: function CanvasGraphics_setLineJoin(style) {
4133
      this.ctx.lineJoin = LINE_JOIN_STYLES[style];
4134
    },
4135
    setMiterLimit: function CanvasGraphics_setMiterLimit(limit) {
4136
      this.ctx.miterLimit = limit;
4137
    },
4138
    setDash: function CanvasGraphics_setDash(dashArray, dashPhase) {
4139
      var ctx = this.ctx;
4140
      if (ctx.setLineDash !== undefined) {
4141
        ctx.setLineDash(dashArray);
4142
        ctx.lineDashOffset = dashPhase;
4143
      } else {
4144
        ctx.mozDash = dashArray;
4145
        ctx.mozDashOffset = dashPhase;
4146
      }
4147
    },
4148
    setRenderingIntent: function CanvasGraphics_setRenderingIntent(intent) {
0 ignored issues
show
Unused Code introduced by
The parameter intent is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
4149
      // Maybe if we one day fully support color spaces this will be important
4150
      // for now we can ignore.
4151
      // TODO set rendering intent?
4152
    },
4153
    setFlatness: function CanvasGraphics_setFlatness(flatness) {
0 ignored issues
show
Unused Code introduced by
The parameter flatness is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
4154
      // There's no way to control this with canvas, but we can safely ignore.
4155
      // TODO set flatness?
4156
    },
4157
    setGState: function CanvasGraphics_setGState(states) {
4158
      for (var i = 0, ii = states.length; i < ii; i++) {
4159
        var state = states[i];
4160
        var key = state[0];
4161
        var value = state[1];
4162
4163
        switch (key) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4164
          case 'LW':
4165
            this.setLineWidth(value);
4166
            break;
4167
          case 'LC':
4168
            this.setLineCap(value);
4169
            break;
4170
          case 'LJ':
4171
            this.setLineJoin(value);
4172
            break;
4173
          case 'ML':
4174
            this.setMiterLimit(value);
4175
            break;
4176
          case 'D':
4177
            this.setDash(value[0], value[1]);
4178
            break;
4179
          case 'RI':
4180
            this.setRenderingIntent(value);
4181
            break;
4182
          case 'FL':
4183
            this.setFlatness(value);
4184
            break;
4185
          case 'Font':
4186
            this.setFont(value[0], value[1]);
4187
            break;
4188
          case 'CA':
4189
            this.current.strokeAlpha = state[1];
4190
            break;
4191
          case 'ca':
4192
            this.current.fillAlpha = state[1];
4193
            this.ctx.globalAlpha = state[1];
4194
            break;
4195
          case 'BM':
4196
            if (value && value.name && (value.name !== 'Normal')) {
4197
              var mode = value.name.replace(/([A-Z])/g,
4198
                function(c) {
4199
                  return '-' + c.toLowerCase();
4200
                }
4201
              ).substring(1);
4202
              this.ctx.globalCompositeOperation = mode;
4203
              if (this.ctx.globalCompositeOperation !== mode) {
4204
                warn('globalCompositeOperation "' + mode +
4205
                     '" is not supported');
4206
              }
4207
            } else {
4208
              this.ctx.globalCompositeOperation = 'source-over';
4209
            }
4210
            break;
4211
          case 'SMask':
4212
            if (this.current.activeSMask) {
4213
              this.endSMaskGroup();
4214
            }
4215
            this.current.activeSMask = value ? this.tempSMask : null;
4216
            if (this.current.activeSMask) {
4217
              this.beginSMaskGroup();
4218
            }
4219
            this.tempSMask = null;
4220
            break;
4221
        }
4222
      }
4223
    },
4224
    beginSMaskGroup: function CanvasGraphics_beginSMaskGroup() {
4225
4226
      var activeSMask = this.current.activeSMask;
4227
      var drawnWidth = activeSMask.canvas.width;
4228
      var drawnHeight = activeSMask.canvas.height;
4229
      var cacheId = 'smaskGroupAt' + this.groupLevel;
4230
      var scratchCanvas = CachedCanvases.getCanvas(
4231
        cacheId, drawnWidth, drawnHeight, true);
4232
4233
      var currentCtx = this.ctx;
4234
      var currentTransform = currentCtx.mozCurrentTransform;
4235
      this.ctx.save();
4236
4237
      var groupCtx = scratchCanvas.context;
4238
      groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
4239
      groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
4240
      groupCtx.transform.apply(groupCtx, currentTransform);
4241
4242
      copyCtxState(currentCtx, groupCtx);
4243
      this.ctx = groupCtx;
4244
      this.setGState([
4245
        ['BM', 'Normal'],
4246
        ['ca', 1],
4247
        ['CA', 1]
4248
      ]);
4249
      this.groupStack.push(currentCtx);
4250
      this.groupLevel++;
4251
    },
4252
    endSMaskGroup: function CanvasGraphics_endSMaskGroup() {
4253
      var groupCtx = this.ctx;
4254
      this.groupLevel--;
4255
      this.ctx = this.groupStack.pop();
4256
4257
      composeSMask(this.ctx, this.current.activeSMask, groupCtx);
4258
      this.ctx.restore();
4259
    },
4260
    save: function CanvasGraphics_save() {
4261
      this.ctx.save();
4262
      var old = this.current;
4263
      this.stateStack.push(old);
4264
      this.current = old.clone();
4265
      this.current.activeSMask = null;
4266
    },
4267
    restore: function CanvasGraphics_restore() {
4268
      if (this.stateStack.length !== 0) {
4269
        if (this.current.activeSMask !== null) {
4270
          this.endSMaskGroup();
4271
        }
4272
4273
        this.current = this.stateStack.pop();
4274
        this.ctx.restore();
4275
4276
        this.cachedGetSinglePixelWidth = null;
4277
      }
4278
    },
4279
    transform: function CanvasGraphics_transform(a, b, c, d, e, f) {
4280
      this.ctx.transform(a, b, c, d, e, f);
4281
4282
      this.cachedGetSinglePixelWidth = null;
4283
    },
4284
4285
    // Path
4286 View Code Duplication
    constructPath: function CanvasGraphics_constructPath(ops, args) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
4287
      var ctx = this.ctx;
4288
      var current = this.current;
4289
      var x = current.x, y = current.y;
4290
      for (var i = 0, j = 0, ii = ops.length; i < ii; i++) {
4291
        switch (ops[i] | 0) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4292
          case OPS.rectangle:
0 ignored issues
show
Bug introduced by
The variable OPS seems to be never declared. If this is a global, consider adding a /** global: OPS */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4293
            x = args[j++];
4294
            y = args[j++];
4295
            var width = args[j++];
4296
            var height = args[j++];
4297
            if (width === 0) {
4298
              width = this.getSinglePixelWidth();
4299
            }
4300
            if (height === 0) {
4301
              height = this.getSinglePixelWidth();
4302
            }
4303
            var xw = x + width;
4304
            var yh = y + height;
4305
            this.ctx.moveTo(x, y);
4306
            this.ctx.lineTo(xw, y);
4307
            this.ctx.lineTo(xw, yh);
4308
            this.ctx.lineTo(x, yh);
4309
            this.ctx.lineTo(x, y);
4310
            this.ctx.closePath();
4311
            break;
4312
          case OPS.moveTo:
4313
            x = args[j++];
4314
            y = args[j++];
4315
            ctx.moveTo(x, y);
4316
            break;
4317
          case OPS.lineTo:
4318
            x = args[j++];
4319
            y = args[j++];
4320
            ctx.lineTo(x, y);
4321
            break;
4322
          case OPS.curveTo:
4323
            x = args[j + 4];
4324
            y = args[j + 5];
4325
            ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3],
4326
                              x, y);
4327
            j += 6;
4328
            break;
4329
          case OPS.curveTo2:
4330
            ctx.bezierCurveTo(x, y, args[j], args[j + 1],
4331
                              args[j + 2], args[j + 3]);
4332
            x = args[j + 2];
4333
            y = args[j + 3];
4334
            j += 4;
4335
            break;
4336
          case OPS.curveTo3:
4337
            x = args[j + 2];
4338
            y = args[j + 3];
4339
            ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
4340
            j += 4;
4341
            break;
4342
          case OPS.closePath:
4343
            ctx.closePath();
4344
            break;
4345
        }
4346
      }
4347
      current.setCurrentPoint(x, y);
4348
    },
4349
    closePath: function CanvasGraphics_closePath() {
4350
      this.ctx.closePath();
4351
    },
4352
    stroke: function CanvasGraphics_stroke(consumePath) {
4353
      consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
4354
      var ctx = this.ctx;
4355
      var strokeColor = this.current.strokeColor;
4356
      // Prevent drawing too thin lines by enforcing a minimum line width.
4357
      ctx.lineWidth = Math.max(this.getSinglePixelWidth() * MIN_WIDTH_FACTOR,
4358
                               this.current.lineWidth);
4359
      // For stroke we want to temporarily change the global alpha to the
4360
      // stroking alpha.
4361
      ctx.globalAlpha = this.current.strokeAlpha;
4362
      if (strokeColor && strokeColor.hasOwnProperty('type') &&
4363
          strokeColor.type === 'Pattern') {
4364
        // for patterns, we transform to pattern space, calculate
4365
        // the pattern, call stroke, and restore to user space
4366
        ctx.save();
4367
        ctx.strokeStyle = strokeColor.getPattern(ctx, this);
4368
        ctx.stroke();
4369
        ctx.restore();
4370
      } else {
4371
        ctx.stroke();
4372
      }
4373
      if (consumePath) {
4374
        this.consumePath();
4375
      }
4376
      // Restore the global alpha to the fill alpha
4377
      ctx.globalAlpha = this.current.fillAlpha;
4378
    },
4379
    closeStroke: function CanvasGraphics_closeStroke() {
4380
      this.closePath();
4381
      this.stroke();
4382
    },
4383
    fill: function CanvasGraphics_fill(consumePath) {
4384
      consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
4385
      var ctx = this.ctx;
4386
      var fillColor = this.current.fillColor;
4387
      var isPatternFill = this.current.patternFill;
4388
      var needRestore = false;
4389
4390
      if (isPatternFill) {
4391
        ctx.save();
4392
        ctx.fillStyle = fillColor.getPattern(ctx, this);
4393
        needRestore = true;
4394
      }
4395
4396
      if (this.pendingEOFill) {
4397
        if (ctx.mozFillRule !== undefined) {
4398
          ctx.mozFillRule = 'evenodd';
4399
          ctx.fill();
4400
          ctx.mozFillRule = 'nonzero';
4401
        } else {
4402
          try {
4403
            ctx.fill('evenodd');
4404
          } catch (ex) {
4405
            // shouldn't really happen, but browsers might think differently
4406
            ctx.fill();
4407
          }
4408
        }
4409
        this.pendingEOFill = false;
4410
      } else {
4411
        ctx.fill();
4412
      }
4413
4414
      if (needRestore) {
4415
        ctx.restore();
4416
      }
4417
      if (consumePath) {
4418
        this.consumePath();
4419
      }
4420
    },
4421
    eoFill: function CanvasGraphics_eoFill() {
4422
      this.pendingEOFill = true;
4423
      this.fill();
4424
    },
4425
    fillStroke: function CanvasGraphics_fillStroke() {
4426
      this.fill(false);
4427
      this.stroke(false);
4428
4429
      this.consumePath();
4430
    },
4431
    eoFillStroke: function CanvasGraphics_eoFillStroke() {
4432
      this.pendingEOFill = true;
4433
      this.fillStroke();
4434
    },
4435
    closeFillStroke: function CanvasGraphics_closeFillStroke() {
4436
      this.closePath();
4437
      this.fillStroke();
4438
    },
4439
    closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() {
4440
      this.pendingEOFill = true;
4441
      this.closePath();
4442
      this.fillStroke();
4443
    },
4444
    endPath: function CanvasGraphics_endPath() {
4445
      this.consumePath();
4446
    },
4447
4448
    // Clipping
4449
    clip: function CanvasGraphics_clip() {
4450
      this.pendingClip = NORMAL_CLIP;
4451
    },
4452
    eoClip: function CanvasGraphics_eoClip() {
4453
      this.pendingClip = EO_CLIP;
4454
    },
4455
4456
    // Text
4457
    beginText: function CanvasGraphics_beginText() {
4458
      this.current.textMatrix = IDENTITY_MATRIX;
4459
      this.current.textMatrixScale = 1;
4460
      this.current.x = this.current.lineX = 0;
4461
      this.current.y = this.current.lineY = 0;
4462
    },
4463
    endText: function CanvasGraphics_endText() {
4464
      var paths = this.pendingTextPaths;
4465
      var ctx = this.ctx;
4466
      if (paths === undefined) {
4467
        ctx.beginPath();
4468
        return;
4469
      }
4470
4471
      ctx.save();
4472
      ctx.beginPath();
4473
      for (var i = 0; i < paths.length; i++) {
4474
        var path = paths[i];
4475
        ctx.setTransform.apply(ctx, path.transform);
4476
        ctx.translate(path.x, path.y);
4477
        path.addToPath(ctx, path.fontSize);
4478
      }
4479
      ctx.restore();
4480
      ctx.clip();
4481
      ctx.beginPath();
4482
      delete this.pendingTextPaths;
4483
    },
4484
    setCharSpacing: function CanvasGraphics_setCharSpacing(spacing) {
4485
      this.current.charSpacing = spacing;
4486
    },
4487
    setWordSpacing: function CanvasGraphics_setWordSpacing(spacing) {
4488
      this.current.wordSpacing = spacing;
4489
    },
4490
    setHScale: function CanvasGraphics_setHScale(scale) {
4491
      this.current.textHScale = scale / 100;
4492
    },
4493
    setLeading: function CanvasGraphics_setLeading(leading) {
4494
      this.current.leading = -leading;
4495
    },
4496
    setFont: function CanvasGraphics_setFont(fontRefName, size) {
4497
      var fontObj = this.commonObjs.get(fontRefName);
4498
      var current = this.current;
4499
4500
      if (!fontObj) {
4501
        error('Can\'t find font for ' + fontRefName);
4502
      }
4503
4504
      current.fontMatrix = (fontObj.fontMatrix ?
4505
                            fontObj.fontMatrix : FONT_IDENTITY_MATRIX);
4506
4507
      // A valid matrix needs all main diagonal elements to be non-zero
4508
      // This also ensures we bypass FF bugzilla bug #719844.
4509
      if (current.fontMatrix[0] === 0 ||
4510
          current.fontMatrix[3] === 0) {
4511
        warn('Invalid font matrix for font ' + fontRefName);
4512
      }
4513
4514
      // The spec for Tf (setFont) says that 'size' specifies the font 'scale',
4515
      // and in some docs this can be negative (inverted x-y axes).
4516
      if (size < 0) {
4517
        size = -size;
4518
        current.fontDirection = -1;
4519
      } else {
4520
        current.fontDirection = 1;
4521
      }
4522
4523
      this.current.font = fontObj;
4524
      this.current.fontSize = size;
4525
4526
      if (fontObj.isType3Font) {
4527
        return; // we don't need ctx.font for Type3 fonts
4528
      }
4529
4530
      var name = fontObj.loadedName || 'sans-serif';
4531
      var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
4532
                                 (fontObj.bold ? 'bold' : 'normal');
4533
4534
      var italic = fontObj.italic ? 'italic' : 'normal';
4535
      var typeface = '"' + name + '", ' + fontObj.fallbackName;
4536
4537
      // Some font backends cannot handle fonts below certain size.
4538
      // Keeping the font at minimal size and using the fontSizeScale to change
4539
      // the current transformation matrix before the fillText/strokeText.
4540
      // See https://bugzilla.mozilla.org/show_bug.cgi?id=726227
4541
      var browserFontSize = size < MIN_FONT_SIZE ? MIN_FONT_SIZE :
4542
                            size > MAX_FONT_SIZE ? MAX_FONT_SIZE : size;
4543
      this.current.fontSizeScale = size / browserFontSize;
4544
4545
      var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
4546
      this.ctx.font = rule;
4547
    },
4548
    setTextRenderingMode: function CanvasGraphics_setTextRenderingMode(mode) {
4549
      this.current.textRenderingMode = mode;
4550
    },
4551
    setTextRise: function CanvasGraphics_setTextRise(rise) {
4552
      this.current.textRise = rise;
4553
    },
4554
    moveText: function CanvasGraphics_moveText(x, y) {
4555
      this.current.x = this.current.lineX += x;
4556
      this.current.y = this.current.lineY += y;
4557
    },
4558
    setLeadingMoveText: function CanvasGraphics_setLeadingMoveText(x, y) {
4559
      this.setLeading(-y);
4560
      this.moveText(x, y);
4561
    },
4562
    setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
4563
      this.current.textMatrix = [a, b, c, d, e, f];
4564
      this.current.textMatrixScale = Math.sqrt(a * a + b * b);
4565
4566
      this.current.x = this.current.lineX = 0;
4567
      this.current.y = this.current.lineY = 0;
4568
    },
4569
    nextLine: function CanvasGraphics_nextLine() {
4570
      this.moveText(0, this.current.leading);
4571
    },
4572
4573
    paintChar: function CanvasGraphics_paintChar(character, x, y) {
4574
      var ctx = this.ctx;
4575
      var current = this.current;
4576
      var font = current.font;
4577
      var textRenderingMode = current.textRenderingMode;
4578
      var fontSize = current.fontSize / current.fontSizeScale;
4579
      var fillStrokeMode = textRenderingMode &
4580
        TextRenderingMode.FILL_STROKE_MASK;
4581
      var isAddToPathSet = !!(textRenderingMode &
4582
        TextRenderingMode.ADD_TO_PATH_FLAG);
4583
4584
      var addToPath;
4585
      if (font.disableFontFace || isAddToPathSet) {
4586
        addToPath = font.getPathGenerator(this.commonObjs, character);
4587
      }
4588
4589
      if (font.disableFontFace) {
4590
        ctx.save();
4591
        ctx.translate(x, y);
4592
        ctx.beginPath();
4593
        addToPath(ctx, fontSize);
4594
        if (fillStrokeMode === TextRenderingMode.FILL ||
4595
            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
4596
          ctx.fill();
4597
        }
4598
        if (fillStrokeMode === TextRenderingMode.STROKE ||
4599
            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
4600
          ctx.stroke();
4601
        }
4602
        ctx.restore();
4603
      } else {
4604
        if (fillStrokeMode === TextRenderingMode.FILL ||
4605
            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
4606
          ctx.fillText(character, x, y);
4607
        }
4608
        if (fillStrokeMode === TextRenderingMode.STROKE ||
4609
            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
4610
          ctx.strokeText(character, x, y);
4611
        }
4612
      }
4613
4614
      if (isAddToPathSet) {
4615
        var paths = this.pendingTextPaths || (this.pendingTextPaths = []);
4616
        paths.push({
4617
          transform: ctx.mozCurrentTransform,
4618
          x: x,
4619
          y: y,
4620
          fontSize: fontSize,
4621
          addToPath: addToPath
0 ignored issues
show
Bug introduced by
The variable addToPath does not seem to be initialized in case font.disableFontFace || isAddToPathSet on line 4585 is false. Are you sure this can never be the case?
Loading history...
4622
        });
4623
      }
4624
    },
4625
4626
    get isFontSubpixelAAEnabled() {
4627
      // Checks if anti-aliasing is enabled when scaled text is painted.
4628
      // On Windows GDI scaled fonts looks bad.
4629
      var ctx = document.createElement('canvas').getContext('2d');
4630
      ctx.scale(1.5, 1);
4631
      ctx.fillText('I', 0, 10);
4632
      var data = ctx.getImageData(0, 0, 10, 10).data;
4633
      var enabled = false;
4634
      for (var i = 3; i < data.length; i += 4) {
4635
        if (data[i] > 0 && data[i] < 255) {
4636
          enabled = true;
4637
          break;
4638
        }
4639
      }
4640
      return shadow(this, 'isFontSubpixelAAEnabled', enabled);
4641
    },
4642
4643
    showText: function CanvasGraphics_showText(glyphs) {
4644
      var current = this.current;
4645
      var font = current.font;
4646
      if (font.isType3Font) {
4647
        return this.showType3Text(glyphs);
4648
      }
4649
4650
      var fontSize = current.fontSize;
4651
      if (fontSize === 0) {
4652
        return;
4653
      }
4654
4655
      var ctx = this.ctx;
4656
      var fontSizeScale = current.fontSizeScale;
4657
      var charSpacing = current.charSpacing;
4658
      var wordSpacing = current.wordSpacing;
4659
      var fontDirection = current.fontDirection;
4660
      var textHScale = current.textHScale * fontDirection;
4661
      var glyphsLength = glyphs.length;
4662
      var vertical = font.vertical;
4663
      var defaultVMetrics = font.defaultVMetrics;
4664
      var widthAdvanceScale = fontSize * current.fontMatrix[0];
4665
4666
      var simpleFillText =
4667
        current.textRenderingMode === TextRenderingMode.FILL &&
4668
        !font.disableFontFace;
4669
4670
      ctx.save();
4671
      ctx.transform.apply(ctx, current.textMatrix);
4672
      ctx.translate(current.x, current.y + current.textRise);
4673
4674
      if (fontDirection > 0) {
4675
        ctx.scale(textHScale, -1);
4676
      } else {
4677
        ctx.scale(textHScale, 1);
4678
      }
4679
4680
      var lineWidth = current.lineWidth;
4681
      var scale = current.textMatrixScale;
4682
      if (scale === 0 || lineWidth === 0) {
4683
        var fillStrokeMode = current.textRenderingMode &
4684
          TextRenderingMode.FILL_STROKE_MASK;
4685
        if (fillStrokeMode === TextRenderingMode.STROKE ||
4686
            fillStrokeMode === TextRenderingMode.FILL_STROKE) {
4687
          this.cachedGetSinglePixelWidth = null;
4688
          lineWidth = this.getSinglePixelWidth() * MIN_WIDTH_FACTOR;
4689
        }
4690
      } else {
4691
        lineWidth /= scale;
4692
      }
4693
4694
      if (fontSizeScale !== 1.0) {
4695
        ctx.scale(fontSizeScale, fontSizeScale);
4696
        lineWidth /= fontSizeScale;
4697
      }
4698
4699
      ctx.lineWidth = lineWidth;
4700
4701
      var x = 0, i;
4702
      for (i = 0; i < glyphsLength; ++i) {
4703
        var glyph = glyphs[i];
4704
        if (glyph === null) {
4705
          // word break
4706
          x += fontDirection * wordSpacing;
4707
          continue;
4708
        } else if (isNum(glyph)) {
4709
          x += -glyph * fontSize * 0.001;
4710
          continue;
4711
        }
4712
4713
        var restoreNeeded = false;
4714
        var character = glyph.fontChar;
4715
        var accent = glyph.accent;
4716
        var scaledX, scaledY, scaledAccentX, scaledAccentY;
4717
        var width = glyph.width;
4718
        if (vertical) {
4719
          var vmetric, vx, vy;
4720
          vmetric = glyph.vmetric || defaultVMetrics;
4721
          vx = glyph.vmetric ? vmetric[1] : width * 0.5;
4722
          vx = -vx * widthAdvanceScale;
4723
          vy = vmetric[2] * widthAdvanceScale;
4724
4725
          width = vmetric ? -vmetric[0] : width;
4726
          scaledX = vx / fontSizeScale;
4727
          scaledY = (x + vy) / fontSizeScale;
4728
        } else {
4729
          scaledX = x / fontSizeScale;
4730
          scaledY = 0;
4731
        }
4732
4733
        if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {
4734
          // some standard fonts may not have the exact width, trying to
4735
          // rescale per character
4736
          var measuredWidth = ctx.measureText(character).width * 1000 /
4737
            fontSize * fontSizeScale;
4738
          var characterScaleX = width / measuredWidth;
4739
          restoreNeeded = true;
4740
          ctx.save();
4741
          ctx.scale(characterScaleX, 1);
4742
          scaledX /= characterScaleX;
4743
        }
4744
4745
        if (simpleFillText && !accent) {
4746
          // common case
4747
          ctx.fillText(character, scaledX, scaledY);
4748
        } else {
4749
          this.paintChar(character, scaledX, scaledY);
4750
          if (accent) {
4751
            scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
4752
            scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
4753
            this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
4754
          }
4755
        }
4756
4757
        var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;
4758
        x += charWidth;
4759
4760
        if (restoreNeeded) {
4761
          ctx.restore();
4762
        }
4763
      }
4764
      if (vertical) {
4765
        current.y -= x * textHScale;
4766
      } else {
4767
        current.x += x * textHScale;
4768
      }
4769
      ctx.restore();
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
4770
    },
4771
4772
    showType3Text: function CanvasGraphics_showType3Text(glyphs) {
4773
      // Type3 fonts - each glyph is a "mini-PDF"
4774
      var ctx = this.ctx;
4775
      var current = this.current;
4776
      var font = current.font;
4777
      var fontSize = current.fontSize;
4778
      var fontDirection = current.fontDirection;
4779
      var charSpacing = current.charSpacing;
4780
      var wordSpacing = current.wordSpacing;
4781
      var textHScale = current.textHScale * fontDirection;
4782
      var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
4783
      var glyphsLength = glyphs.length;
4784
      var isTextInvisible =
4785
        current.textRenderingMode === TextRenderingMode.INVISIBLE;
4786
      var i, glyph, width;
4787
4788
      if (isTextInvisible || fontSize === 0) {
4789
        return;
4790
      }
4791
4792
      ctx.save();
4793
      ctx.transform.apply(ctx, current.textMatrix);
4794
      ctx.translate(current.x, current.y);
4795
4796
      ctx.scale(textHScale, fontDirection);
4797
4798
      for (i = 0; i < glyphsLength; ++i) {
4799
        glyph = glyphs[i];
4800
        if (glyph === null) {
4801
          // word break
4802
          this.ctx.translate(wordSpacing, 0);
4803
          current.x += wordSpacing * textHScale;
4804
          continue;
4805
        } else if (isNum(glyph)) {
4806
          var spacingLength = -glyph * 0.001 * fontSize;
4807
          this.ctx.translate(spacingLength, 0);
4808
          current.x += spacingLength * textHScale;
4809
          continue;
4810
        }
4811
4812
        var operatorList = font.charProcOperatorList[glyph.operatorListId];
4813
        if (!operatorList) {
4814
          warn('Type3 character \"' + glyph.operatorListId +
4815
               '\" is not available');
4816
          continue;
4817
        }
4818
        this.processingType3 = glyph;
4819
        this.save();
4820
        ctx.scale(fontSize, fontSize);
4821
        ctx.transform.apply(ctx, fontMatrix);
4822
        this.executeOperatorList(operatorList);
4823
        this.restore();
4824
4825
        var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
4826
        width = transformed[0] * fontSize + charSpacing;
4827
4828
        ctx.translate(width, 0);
4829
        current.x += width * textHScale;
4830
      }
4831
      ctx.restore();
4832
      this.processingType3 = null;
4833
    },
4834
4835
    // Type3 fonts
4836
    setCharWidth: function CanvasGraphics_setCharWidth(xWidth, yWidth) {
0 ignored issues
show
Unused Code introduced by
The parameter yWidth is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter xWidth is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
4837
      // We can safely ignore this since the width should be the same
4838
      // as the width in the Widths array.
4839
    },
4840
    setCharWidthAndBounds: function CanvasGraphics_setCharWidthAndBounds(xWidth,
4841
                                                                        yWidth,
4842
                                                                        llx,
4843
                                                                        lly,
4844
                                                                        urx,
4845
                                                                        ury) {
4846
      // TODO According to the spec we're also suppose to ignore any operators
4847
      // that set color or include images while processing this type3 font.
4848
      this.ctx.rect(llx, lly, urx - llx, ury - lly);
4849
      this.clip();
4850
      this.endPath();
4851
    },
4852
4853
    // Color
4854
    getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) {
4855
      var pattern;
4856
      if (IR[0] === 'TilingPattern') {
4857
        var color = IR[1];
4858
        pattern = new TilingPattern(IR, color, this.ctx, this.objs,
4859
                                    this.commonObjs, this.baseTransform);
4860
      } else {
4861
        pattern = getShadingPatternFromIR(IR);
4862
      }
4863
      return pattern;
4864
    },
4865
    setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) {
4866
      this.current.strokeColor = this.getColorN_Pattern(arguments);
4867
    },
4868
    setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) {
4869
      this.current.fillColor = this.getColorN_Pattern(arguments);
4870
      this.current.patternFill = true;
4871
    },
4872
    setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
4873
      var color = Util.makeCssRgb(r, g, b);
4874
      this.ctx.strokeStyle = color;
4875
      this.current.strokeColor = color;
4876
    },
4877
    setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
4878
      var color = Util.makeCssRgb(r, g, b);
4879
      this.ctx.fillStyle = color;
4880
      this.current.fillColor = color;
4881
      this.current.patternFill = false;
4882
    },
4883
4884
    shadingFill: function CanvasGraphics_shadingFill(patternIR) {
4885
      var ctx = this.ctx;
4886
4887
      this.save();
4888
      var pattern = getShadingPatternFromIR(patternIR);
4889
      ctx.fillStyle = pattern.getPattern(ctx, this, true);
4890
4891
      var inv = ctx.mozCurrentTransformInverse;
4892
      if (inv) {
4893
        var canvas = ctx.canvas;
4894
        var width = canvas.width;
4895
        var height = canvas.height;
4896
4897
        var bl = Util.applyTransform([0, 0], inv);
4898
        var br = Util.applyTransform([0, height], inv);
4899
        var ul = Util.applyTransform([width, 0], inv);
4900
        var ur = Util.applyTransform([width, height], inv);
4901
4902
        var x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
4903
        var y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
4904
        var x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
4905
        var y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
4906
4907
        this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
4908
      } else {
4909
        // HACK to draw the gradient onto an infinite rectangle.
4910
        // PDF gradients are drawn across the entire image while
4911
        // Canvas only allows gradients to be drawn in a rectangle
4912
        // The following bug should allow us to remove this.
4913
        // https://bugzilla.mozilla.org/show_bug.cgi?id=664884
4914
4915
        this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
4916
      }
4917
4918
      this.restore();
4919
    },
4920
4921
    // Images
4922
    beginInlineImage: function CanvasGraphics_beginInlineImage() {
4923
      error('Should not call beginInlineImage');
4924
    },
4925
    beginImageData: function CanvasGraphics_beginImageData() {
4926
      error('Should not call beginImageData');
4927
    },
4928
4929
    paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix,
4930
                                                                        bbox) {
4931
      this.save();
4932
      this.baseTransformStack.push(this.baseTransform);
4933
4934
      if (isArray(matrix) && 6 === matrix.length) {
4935
        this.transform.apply(this, matrix);
4936
      }
4937
4938
      this.baseTransform = this.ctx.mozCurrentTransform;
4939
4940
      if (isArray(bbox) && 4 === bbox.length) {
4941
        var width = bbox[2] - bbox[0];
4942
        var height = bbox[3] - bbox[1];
4943
        this.ctx.rect(bbox[0], bbox[1], width, height);
4944
        this.clip();
4945
        this.endPath();
4946
      }
4947
    },
4948
4949
    paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() {
4950
      this.restore();
4951
      this.baseTransform = this.baseTransformStack.pop();
4952
    },
4953
4954
    beginGroup: function CanvasGraphics_beginGroup(group) {
4955
      this.save();
4956
      var currentCtx = this.ctx;
4957
      // TODO non-isolated groups - according to Rik at adobe non-isolated
4958
      // group results aren't usually that different and they even have tools
4959
      // that ignore this setting. Notes from Rik on implmenting:
4960
      // - When you encounter an transparency group, create a new canvas with
4961
      // the dimensions of the bbox
4962
      // - copy the content from the previous canvas to the new canvas
4963
      // - draw as usual
4964
      // - remove the backdrop alpha:
4965
      // alphaNew = 1 - (1 - alpha)/(1 - alphaBackdrop) with 'alpha' the alpha
4966
      // value of your transparency group and 'alphaBackdrop' the alpha of the
4967
      // backdrop
4968
      // - remove background color:
4969
      // colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)
4970
      if (!group.isolated) {
4971
        info('TODO: Support non-isolated groups.');
4972
      }
4973
4974
      // TODO knockout - supposedly possible with the clever use of compositing
4975
      // modes.
4976
      if (group.knockout) {
4977
        warn('Knockout groups not supported.');
4978
      }
4979
4980
      var currentTransform = currentCtx.mozCurrentTransform;
4981
      if (group.matrix) {
4982
        currentCtx.transform.apply(currentCtx, group.matrix);
4983
      }
4984
      assert(group.bbox, 'Bounding box is required.');
4985
4986
      // Based on the current transform figure out how big the bounding box
4987
      // will actually be.
4988
      var bounds = Util.getAxialAlignedBoundingBox(
4989
                    group.bbox,
4990
                    currentCtx.mozCurrentTransform);
4991
      // Clip the bounding box to the current canvas.
4992
      var canvasBounds = [0,
4993
                          0,
4994
                          currentCtx.canvas.width,
4995
                          currentCtx.canvas.height];
4996
      bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
4997
      // Use ceil in case we're between sizes so we don't create canvas that is
4998
      // too small and make the canvas at least 1x1 pixels.
4999
      var offsetX = Math.floor(bounds[0]);
5000
      var offsetY = Math.floor(bounds[1]);
5001
      var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
5002
      var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
5003
      var scaleX = 1, scaleY = 1;
5004
      if (drawnWidth > MAX_GROUP_SIZE) {
5005
        scaleX = drawnWidth / MAX_GROUP_SIZE;
5006
        drawnWidth = MAX_GROUP_SIZE;
5007
      }
5008
      if (drawnHeight > MAX_GROUP_SIZE) {
5009
        scaleY = drawnHeight / MAX_GROUP_SIZE;
5010
        drawnHeight = MAX_GROUP_SIZE;
5011
      }
5012
5013
      var cacheId = 'groupAt' + this.groupLevel;
5014
      if (group.smask) {
5015
        // Using two cache entries is case if masks are used one after another.
5016
        cacheId +=  '_smask_' + ((this.smaskCounter++) % 2);
5017
      }
5018
      var scratchCanvas = CachedCanvases.getCanvas(
5019
        cacheId, drawnWidth, drawnHeight, true);
5020
      var groupCtx = scratchCanvas.context;
5021
5022
      // Since we created a new canvas that is just the size of the bounding box
5023
      // we have to translate the group ctx.
5024
      groupCtx.scale(1 / scaleX, 1 / scaleY);
5025
      groupCtx.translate(-offsetX, -offsetY);
5026
      groupCtx.transform.apply(groupCtx, currentTransform);
5027
5028
      if (group.smask) {
5029
        // Saving state and cached mask to be used in setGState.
5030
        this.smaskStack.push({
5031
          canvas: scratchCanvas.canvas,
5032
          context: groupCtx,
5033
          offsetX: offsetX,
5034
          offsetY: offsetY,
5035
          scaleX: scaleX,
5036
          scaleY: scaleY,
5037
          subtype: group.smask.subtype,
5038
          backdrop: group.smask.backdrop
5039
        });
5040
      } else {
5041
        // Setup the current ctx so when the group is popped we draw it at the
5042
        // right location.
5043
        currentCtx.setTransform(1, 0, 0, 1, 0, 0);
5044
        currentCtx.translate(offsetX, offsetY);
5045
        currentCtx.scale(scaleX, scaleY);
5046
      }
5047
      // The transparency group inherits all off the current graphics state
5048
      // except the blend mode, soft mask, and alpha constants.
5049
      copyCtxState(currentCtx, groupCtx);
5050
      this.ctx = groupCtx;
5051
      this.setGState([
5052
        ['BM', 'Normal'],
5053
        ['ca', 1],
5054
        ['CA', 1]
5055
      ]);
5056
      this.groupStack.push(currentCtx);
5057
      this.groupLevel++;
5058
    },
5059
5060
    endGroup: function CanvasGraphics_endGroup(group) {
5061
      this.groupLevel--;
5062
      var groupCtx = this.ctx;
5063
      this.ctx = this.groupStack.pop();
5064
      // Turn off image smoothing to avoid sub pixel interpolation which can
5065
      // look kind of blurry for some pdfs.
5066
      if (this.ctx.imageSmoothingEnabled !== undefined) {
5067
        this.ctx.imageSmoothingEnabled = false;
5068
      } else {
5069
        this.ctx.mozImageSmoothingEnabled = false;
5070
      }
5071
      if (group.smask) {
5072
        this.tempSMask = this.smaskStack.pop();
5073
      } else {
5074
        this.ctx.drawImage(groupCtx.canvas, 0, 0);
5075
      }
5076
      this.restore();
5077
    },
5078
5079
    beginAnnotations: function CanvasGraphics_beginAnnotations() {
5080
      this.save();
5081
      this.current = new CanvasExtraState();
5082
    },
5083
5084
    endAnnotations: function CanvasGraphics_endAnnotations() {
5085
      this.restore();
5086
    },
5087
5088
    beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform,
5089
                                                             matrix) {
5090
      this.save();
5091
5092
      if (isArray(rect) && 4 === rect.length) {
5093
        var width = rect[2] - rect[0];
5094
        var height = rect[3] - rect[1];
5095
        this.ctx.rect(rect[0], rect[1], width, height);
5096
        this.clip();
5097
        this.endPath();
5098
      }
5099
5100
      this.transform.apply(this, transform);
5101
      this.transform.apply(this, matrix);
5102
    },
5103
5104
    endAnnotation: function CanvasGraphics_endAnnotation() {
5105
      this.restore();
5106
    },
5107
5108
    paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
5109
      var domImage = this.objs.get(objId);
5110
      if (!domImage) {
5111
        warn('Dependent image isn\'t ready yet');
5112
        return;
5113
      }
5114
5115
      this.save();
5116
5117
      var ctx = this.ctx;
5118
      // scale the image to the unit square
5119
      ctx.scale(1 / w, -1 / h);
5120
5121
      ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
5122
                    0, -h, w, h);
5123
      if (this.imageLayer) {
5124
        var currentTransform = ctx.mozCurrentTransformInverse;
5125
        var position = this.getCanvasPosition(0, 0);
5126
        this.imageLayer.appendImage({
5127
          objId: objId,
5128
          left: position[0],
5129
          top: position[1],
5130
          width: w / currentTransform[0],
5131
          height: h / currentTransform[3]
5132
        });
5133
      }
5134
      this.restore();
5135
    },
5136
5137
    paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) {
5138
      var ctx = this.ctx;
5139
      var width = img.width, height = img.height;
5140
      var fillColor = this.current.fillColor;
5141
      var isPatternFill = this.current.patternFill;
5142
5143
      var glyph = this.processingType3;
5144
5145
      if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) {
5146
        if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {
5147
          glyph.compiled =
5148
            compileType3Glyph({data: img.data, width: width, height: height});
5149
        } else {
5150
          glyph.compiled = null;
5151
        }
5152
      }
5153
5154
      if (glyph && glyph.compiled) {
5155
        glyph.compiled(ctx);
5156
        return;
5157
      }
5158
5159
      var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
5160
      var maskCtx = maskCanvas.context;
5161
      maskCtx.save();
5162
5163
      putBinaryImageMask(maskCtx, img);
5164
5165
      maskCtx.globalCompositeOperation = 'source-in';
5166
5167
      maskCtx.fillStyle = isPatternFill ?
5168
                          fillColor.getPattern(maskCtx, this) : fillColor;
5169
      maskCtx.fillRect(0, 0, width, height);
5170
5171
      maskCtx.restore();
5172
5173
      this.paintInlineImageXObject(maskCanvas.canvas);
5174
    },
5175
5176
    paintImageMaskXObjectRepeat:
5177
      function CanvasGraphics_paintImageMaskXObjectRepeat(imgData, scaleX,
5178
                                                          scaleY, positions) {
5179
      var width = imgData.width;
5180
      var height = imgData.height;
5181
      var fillColor = this.current.fillColor;
5182
      var isPatternFill = this.current.patternFill;
5183
5184
      var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
5185
      var maskCtx = maskCanvas.context;
5186
      maskCtx.save();
5187
5188
      putBinaryImageMask(maskCtx, imgData);
5189
5190
      maskCtx.globalCompositeOperation = 'source-in';
5191
5192
      maskCtx.fillStyle = isPatternFill ?
5193
                          fillColor.getPattern(maskCtx, this) : fillColor;
5194
      maskCtx.fillRect(0, 0, width, height);
5195
5196
      maskCtx.restore();
5197
5198
      var ctx = this.ctx;
5199
      for (var i = 0, ii = positions.length; i < ii; i += 2) {
5200
        ctx.save();
5201
        ctx.transform(scaleX, 0, 0, scaleY, positions[i], positions[i + 1]);
5202
        ctx.scale(1, -1);
5203
        ctx.drawImage(maskCanvas.canvas, 0, 0, width, height,
5204
          0, -1, 1, 1);
5205
        ctx.restore();
5206
      }
5207
    },
5208
5209
    paintImageMaskXObjectGroup:
5210
      function CanvasGraphics_paintImageMaskXObjectGroup(images) {
5211
      var ctx = this.ctx;
5212
5213
      var fillColor = this.current.fillColor;
5214
      var isPatternFill = this.current.patternFill;
5215
      for (var i = 0, ii = images.length; i < ii; i++) {
5216
        var image = images[i];
5217
        var width = image.width, height = image.height;
5218
5219
        var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
5220
        var maskCtx = maskCanvas.context;
5221
        maskCtx.save();
5222
5223
        putBinaryImageMask(maskCtx, image);
5224
5225
        maskCtx.globalCompositeOperation = 'source-in';
5226
5227
        maskCtx.fillStyle = isPatternFill ?
5228
                            fillColor.getPattern(maskCtx, this) : fillColor;
5229
        maskCtx.fillRect(0, 0, width, height);
5230
5231
        maskCtx.restore();
5232
5233
        ctx.save();
5234
        ctx.transform.apply(ctx, image.transform);
5235
        ctx.scale(1, -1);
5236
        ctx.drawImage(maskCanvas.canvas, 0, 0, width, height,
5237
                      0, -1, 1, 1);
5238
        ctx.restore();
5239
      }
5240
    },
5241
5242
    paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
5243
      var imgData = this.objs.get(objId);
5244
      if (!imgData) {
5245
        warn('Dependent image isn\'t ready yet');
5246
        return;
5247
      }
5248
5249
      this.paintInlineImageXObject(imgData);
5250
    },
5251
5252
    paintImageXObjectRepeat:
5253
      function CanvasGraphics_paintImageXObjectRepeat(objId, scaleX, scaleY,
5254
                                                          positions) {
5255
      var imgData = this.objs.get(objId);
5256
      if (!imgData) {
5257
        warn('Dependent image isn\'t ready yet');
5258
        return;
5259
      }
5260
5261
      var width = imgData.width;
5262
      var height = imgData.height;
5263
      var map = [];
5264
      for (var i = 0, ii = positions.length; i < ii; i += 2) {
5265
        map.push({transform: [scaleX, 0, 0, scaleY, positions[i],
5266
                 positions[i + 1]], x: 0, y: 0, w: width, h: height});
5267
      }
5268
      this.paintInlineImageXObjectGroup(imgData, map);
5269
    },
5270
5271
    paintInlineImageXObject:
5272
      function CanvasGraphics_paintInlineImageXObject(imgData) {
5273
      var width = imgData.width;
5274
      var height = imgData.height;
5275
      var ctx = this.ctx;
5276
5277
      this.save();
5278
      // scale the image to the unit square
5279
      ctx.scale(1 / width, -1 / height);
5280
5281
      var currentTransform = ctx.mozCurrentTransformInverse;
5282
      var a = currentTransform[0], b = currentTransform[1];
5283
      var widthScale = Math.max(Math.sqrt(a * a + b * b), 1);
5284
      var c = currentTransform[2], d = currentTransform[3];
5285
      var heightScale = Math.max(Math.sqrt(c * c + d * d), 1);
5286
5287
      var imgToPaint, tmpCanvas;
5288
      // instanceof HTMLElement does not work in jsdom node.js module
5289
      if (imgData instanceof HTMLElement || !imgData.data) {
0 ignored issues
show
Bug introduced by
The variable HTMLElement seems to be never declared. If this is a global, consider adding a /** global: HTMLElement */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
5290
        imgToPaint = imgData;
5291
      } else {
5292
        tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
5293
        var tmpCtx = tmpCanvas.context;
5294
        putBinaryImageData(tmpCtx, imgData);
5295
        imgToPaint = tmpCanvas.canvas;
5296
      }
5297
5298
      var paintWidth = width, paintHeight = height;
5299
      var tmpCanvasId = 'prescale1';
5300
      // Vertial or horizontal scaling shall not be more than 2 to not loose the
5301
      // pixels during drawImage operation, painting on the temporary canvas(es)
5302
      // that are twice smaller in size
5303
      while ((widthScale > 2 && paintWidth > 1) ||
5304
             (heightScale > 2 && paintHeight > 1)) {
5305
        var newWidth = paintWidth, newHeight = paintHeight;
5306
        if (widthScale > 2 && paintWidth > 1) {
5307
          newWidth = Math.ceil(paintWidth / 2);
5308
          widthScale /= paintWidth / newWidth;
5309
        }
5310
        if (heightScale > 2 && paintHeight > 1) {
5311
          newHeight = Math.ceil(paintHeight / 2);
5312
          heightScale /= paintHeight / newHeight;
5313
        }
5314
        tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
5315
        tmpCtx = tmpCanvas.context;
5316
        tmpCtx.clearRect(0, 0, newWidth, newHeight);
5317
        tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
5318
                                     0, 0, newWidth, newHeight);
5319
        imgToPaint = tmpCanvas.canvas;
5320
        paintWidth = newWidth;
5321
        paintHeight = newHeight;
5322
        tmpCanvasId = tmpCanvasId === 'prescale1' ? 'prescale2' : 'prescale1';
5323
      }
5324
      ctx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
5325
                                0, -height, width, height);
5326
5327
      if (this.imageLayer) {
5328
        var position = this.getCanvasPosition(0, -height);
5329
        this.imageLayer.appendImage({
5330
          imgData: imgData,
5331
          left: position[0],
5332
          top: position[1],
5333
          width: width / currentTransform[0],
5334
          height: height / currentTransform[3]
5335
        });
5336
      }
5337
      this.restore();
5338
    },
5339
5340
    paintInlineImageXObjectGroup:
5341
      function CanvasGraphics_paintInlineImageXObjectGroup(imgData, map) {
5342
      var ctx = this.ctx;
5343
      var w = imgData.width;
5344
      var h = imgData.height;
5345
5346
      var tmpCanvas = CachedCanvases.getCanvas('inlineImage', w, h);
5347
      var tmpCtx = tmpCanvas.context;
5348
      putBinaryImageData(tmpCtx, imgData);
5349
5350
      for (var i = 0, ii = map.length; i < ii; i++) {
5351
        var entry = map[i];
5352
        ctx.save();
5353
        ctx.transform.apply(ctx, entry.transform);
5354
        ctx.scale(1, -1);
5355
        ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h,
5356
                      0, -1, 1, 1);
5357
        if (this.imageLayer) {
5358
          var position = this.getCanvasPosition(entry.x, entry.y);
5359
          this.imageLayer.appendImage({
5360
            imgData: imgData,
5361
            left: position[0],
5362
            top: position[1],
5363
            width: w,
5364
            height: h
5365
          });
5366
        }
5367
        ctx.restore();
5368
      }
5369
    },
5370
5371
    paintSolidColorImageMask:
5372
      function CanvasGraphics_paintSolidColorImageMask() {
5373
        this.ctx.fillRect(0, 0, 1, 1);
5374
    },
5375
5376
    // Marked content
5377
5378
    markPoint: function CanvasGraphics_markPoint(tag) {
0 ignored issues
show
Unused Code introduced by
The parameter tag is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
5379
      // TODO Marked content.
5380
    },
5381
    markPointProps: function CanvasGraphics_markPointProps(tag, properties) {
0 ignored issues
show
Unused Code introduced by
The parameter tag is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter properties is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
5382
      // TODO Marked content.
5383
    },
5384
    beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) {
0 ignored issues
show
Unused Code introduced by
The parameter tag is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
5385
      // TODO Marked content.
5386
    },
5387
    beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps(
5388
                                        tag, properties) {
0 ignored issues
show
Unused Code introduced by
The parameter tag is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter properties is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
5389
      // TODO Marked content.
5390
    },
5391
    endMarkedContent: function CanvasGraphics_endMarkedContent() {
5392
      // TODO Marked content.
5393
    },
5394
5395
    // Compatibility
5396
5397
    beginCompat: function CanvasGraphics_beginCompat() {
5398
      // TODO ignore undefined operators (should we do that anyway?)
5399
    },
5400
    endCompat: function CanvasGraphics_endCompat() {
5401
      // TODO stop ignoring undefined operators
5402
    },
5403
5404
    // Helper functions
5405
5406
    consumePath: function CanvasGraphics_consumePath() {
5407
      var ctx = this.ctx;
5408
      if (this.pendingClip) {
5409
        if (this.pendingClip === EO_CLIP) {
5410
          if (ctx.mozFillRule !== undefined) {
5411
            ctx.mozFillRule = 'evenodd';
5412
            ctx.clip();
5413
            ctx.mozFillRule = 'nonzero';
5414
          } else {
5415
            try {
5416
              ctx.clip('evenodd');
5417
            } catch (ex) {
5418
              // shouldn't really happen, but browsers might think differently
5419
              ctx.clip();
5420
            }
5421
          }
5422
        } else {
5423
          ctx.clip();
5424
        }
5425
        this.pendingClip = null;
5426
      }
5427
      ctx.beginPath();
5428
    },
5429
    getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
0 ignored issues
show
Unused Code introduced by
The parameter scale is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
5430
      if (this.cachedGetSinglePixelWidth === null) {
5431
        var inverse = this.ctx.mozCurrentTransformInverse;
5432
        // max of the current horizontal and vertical scale
5433
        this.cachedGetSinglePixelWidth = Math.sqrt(Math.max(
5434
          (inverse[0] * inverse[0] + inverse[1] * inverse[1]),
5435
          (inverse[2] * inverse[2] + inverse[3] * inverse[3])));
5436
      }
5437
      return this.cachedGetSinglePixelWidth;
5438
    },
5439
    getCanvasPosition: function CanvasGraphics_getCanvasPosition(x, y) {
5440
        var transform = this.ctx.mozCurrentTransform;
5441
        return [
5442
          transform[0] * x + transform[2] * y + transform[4],
5443
          transform[1] * x + transform[3] * y + transform[5]
5444
        ];
5445
    }
5446
  };
5447
5448
  for (var op in OPS) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
5449
    CanvasGraphics.prototype[OPS[op]] = CanvasGraphics.prototype[op];
5450
  }
5451
5452
  return CanvasGraphics;
5453
})();
5454
5455
5456
var WebGLUtils = (function WebGLUtilsClosure() {
5457
  function loadShader(gl, code, shaderType) {
5458
    var shader = gl.createShader(shaderType);
5459
    gl.shaderSource(shader, code);
5460
    gl.compileShader(shader);
5461
    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
5462
    if (!compiled) {
5463
      var errorMsg = gl.getShaderInfoLog(shader);
5464
      throw new Error('Error during shader compilation: ' + errorMsg);
5465
    }
5466
    return shader;
5467
  }
5468
  function createVertexShader(gl, code) {
5469
    return loadShader(gl, code, gl.VERTEX_SHADER);
5470
  }
5471
  function createFragmentShader(gl, code) {
5472
    return loadShader(gl, code, gl.FRAGMENT_SHADER);
5473
  }
5474
  function createProgram(gl, shaders) {
5475
    var program = gl.createProgram();
5476
    for (var i = 0, ii = shaders.length; i < ii; ++i) {
5477
      gl.attachShader(program, shaders[i]);
5478
    }
5479
    gl.linkProgram(program);
5480
    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
5481
    if (!linked) {
5482
      var errorMsg = gl.getProgramInfoLog(program);
5483
      throw new Error('Error during program linking: ' + errorMsg);
5484
    }
5485
    return program;
5486
  }
5487
  function createTexture(gl, image, textureId) {
5488
    gl.activeTexture(textureId);
5489
    var texture = gl.createTexture();
5490
    gl.bindTexture(gl.TEXTURE_2D, texture);
5491
5492
    // Set the parameters so we can render any size image.
5493
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
5494
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
5495
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
5496
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
5497
5498
    // Upload the image into the texture.
5499
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
5500
    return texture;
5501
  }
5502
5503
  var currentGL, currentCanvas;
5504
  function generateGL() {
5505
    if (currentGL) {
5506
      return;
5507
    }
5508
    currentCanvas = document.createElement('canvas');
5509
    currentGL = currentCanvas.getContext('webgl',
5510
      { premultipliedalpha: false });
5511
  }
5512
5513
  var smaskVertexShaderCode = '\
5514
  attribute vec2 a_position;                                    \
5515
  attribute vec2 a_texCoord;                                    \
5516
                                                                \
5517
  uniform vec2 u_resolution;                                    \
5518
                                                                \
5519
  varying vec2 v_texCoord;                                      \
5520
                                                                \
5521
  void main() {                                                 \
5522
    vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0;   \
5523
    gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);          \
5524
                                                                \
5525
    v_texCoord = a_texCoord;                                    \
5526
  }                                                             ';
5527
5528
  var smaskFragmentShaderCode = '\
5529
  precision mediump float;                                      \
5530
                                                                \
5531
  uniform vec4 u_backdrop;                                      \
5532
  uniform int u_subtype;                                        \
5533
  uniform sampler2D u_image;                                    \
5534
  uniform sampler2D u_mask;                                     \
5535
                                                                \
5536
  varying vec2 v_texCoord;                                      \
5537
                                                                \
5538
  void main() {                                                 \
5539
    vec4 imageColor = texture2D(u_image, v_texCoord);           \
5540
    vec4 maskColor = texture2D(u_mask, v_texCoord);             \
5541
    if (u_backdrop.a > 0.0) {                                   \
5542
      maskColor.rgb = maskColor.rgb * maskColor.a +             \
5543
                      u_backdrop.rgb * (1.0 - maskColor.a);     \
5544
    }                                                           \
5545
    float lum;                                                  \
5546
    if (u_subtype == 0) {                                       \
5547
      lum = maskColor.a;                                        \
5548
    } else {                                                    \
5549
      lum = maskColor.r * 0.3 + maskColor.g * 0.59 +            \
5550
            maskColor.b * 0.11;                                 \
5551
    }                                                           \
5552
    imageColor.a *= lum;                                        \
5553
    imageColor.rgb *= imageColor.a;                             \
5554
    gl_FragColor = imageColor;                                  \
5555
  }                                                             ';
5556
5557
  var smaskCache = null;
5558
5559
  function initSmaskGL() {
5560
    var canvas, gl;
5561
5562
    generateGL();
5563
    canvas = currentCanvas;
5564
    currentCanvas = null;
5565
    gl = currentGL;
5566
    currentGL = null;
5567
5568
    // setup a GLSL program
5569
    var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
5570
    var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
5571
    var program = createProgram(gl, [vertexShader, fragmentShader]);
5572
    gl.useProgram(program);
5573
5574
    var cache = {};
5575
    cache.gl = gl;
5576
    cache.canvas = canvas;
5577
    cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
5578
    cache.positionLocation = gl.getAttribLocation(program, 'a_position');
5579
    cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
5580
    cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
5581
5582
    var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
5583
    var texLayerLocation = gl.getUniformLocation(program, 'u_image');
5584
    var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
5585
5586
    // provide texture coordinates for the rectangle.
5587
    var texCoordBuffer = gl.createBuffer();
5588
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
5589
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
5590
      0.0,  0.0,
5591
      1.0,  0.0,
5592
      0.0,  1.0,
5593
      0.0,  1.0,
5594
      1.0,  0.0,
5595
      1.0,  1.0]), gl.STATIC_DRAW);
5596
    gl.enableVertexAttribArray(texCoordLocation);
5597
    gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
5598
5599
    gl.uniform1i(texLayerLocation, 0);
5600
    gl.uniform1i(texMaskLocation, 1);
5601
5602
    smaskCache = cache;
5603
  }
5604
5605
  function composeSMask(layer, mask, properties) {
5606
    var width = layer.width, height = layer.height;
5607
5608
    if (!smaskCache) {
5609
      initSmaskGL();
5610
    }
5611
    var cache = smaskCache,canvas = cache.canvas, gl = cache.gl;
5612
    canvas.width = width;
5613
    canvas.height = height;
5614
    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
5615
    gl.uniform2f(cache.resolutionLocation, width, height);
5616
5617
    if (properties.backdrop) {
5618
      gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
5619
                   properties.backdrop[1], properties.backdrop[2], 1);
5620
    } else {
5621
      gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
5622
    }
5623
    gl.uniform1i(cache.subtypeLocation,
5624
                 properties.subtype === 'Luminosity' ? 1 : 0);
5625
5626
    // Create a textures
5627
    var texture = createTexture(gl, layer, gl.TEXTURE0);
5628
    var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
5629
5630
5631
    // Create a buffer and put a single clipspace rectangle in
5632
    // it (2 triangles)
5633
    var buffer = gl.createBuffer();
5634
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
5635
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
5636
      0, 0,
5637
      width, 0,
5638
      0, height,
5639
      0, height,
5640
      width, 0,
5641
      width, height]), gl.STATIC_DRAW);
5642
    gl.enableVertexAttribArray(cache.positionLocation);
5643
    gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
5644
5645
    // draw
5646
    gl.clearColor(0, 0, 0, 0);
5647
    gl.enable(gl.BLEND);
5648
    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
5649
    gl.clear(gl.COLOR_BUFFER_BIT);
5650
5651
    gl.drawArrays(gl.TRIANGLES, 0, 6);
5652
5653
    gl.flush();
5654
5655
    gl.deleteTexture(texture);
5656
    gl.deleteTexture(maskTexture);
5657
    gl.deleteBuffer(buffer);
5658
5659
    return canvas;
5660
  }
5661
5662
  var figuresVertexShaderCode = '\
5663
  attribute vec2 a_position;                                    \
5664
  attribute vec3 a_color;                                       \
5665
                                                                \
5666
  uniform vec2 u_resolution;                                    \
5667
  uniform vec2 u_scale;                                         \
5668
  uniform vec2 u_offset;                                        \
5669
                                                                \
5670
  varying vec4 v_color;                                         \
5671
                                                                \
5672
  void main() {                                                 \
5673
    vec2 position = (a_position + u_offset) * u_scale;          \
5674
    vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0;     \
5675
    gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);          \
5676
                                                                \
5677
    v_color = vec4(a_color / 255.0, 1.0);                       \
5678
  }                                                             ';
5679
5680
  var figuresFragmentShaderCode = '\
5681
  precision mediump float;                                      \
5682
                                                                \
5683
  varying vec4 v_color;                                         \
5684
                                                                \
5685
  void main() {                                                 \
5686
    gl_FragColor = v_color;                                     \
5687
  }                                                             ';
5688
5689
  var figuresCache = null;
5690
5691
  function initFiguresGL() {
5692
    var canvas, gl;
5693
5694
    generateGL();
5695
    canvas = currentCanvas;
5696
    currentCanvas = null;
5697
    gl = currentGL;
5698
    currentGL = null;
5699
5700
    // setup a GLSL program
5701
    var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
5702
    var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
5703
    var program = createProgram(gl, [vertexShader, fragmentShader]);
5704
    gl.useProgram(program);
5705
5706
    var cache = {};
5707
    cache.gl = gl;
5708
    cache.canvas = canvas;
5709
    cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
5710
    cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
5711
    cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
5712
    cache.positionLocation = gl.getAttribLocation(program, 'a_position');
5713
    cache.colorLocation = gl.getAttribLocation(program, 'a_color');
5714
5715
    figuresCache = cache;
5716
  }
5717
5718
  function drawFigures(width, height, backgroundColor, figures, context) {
5719
    if (!figuresCache) {
5720
      initFiguresGL();
5721
    }
5722
    var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
5723
5724
    canvas.width = width;
5725
    canvas.height = height;
5726
    gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
5727
    gl.uniform2f(cache.resolutionLocation, width, height);
5728
5729
    // count triangle points
5730
    var count = 0;
5731
    var i, ii, rows;
5732
    for (i = 0, ii = figures.length; i < ii; i++) {
5733
      switch (figures[i].type) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
5734
        case 'lattice':
5735
          rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
5736
          count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
5737
          break;
5738
        case 'triangles':
5739
          count += figures[i].coords.length;
5740
          break;
5741
      }
5742
    }
5743
    // transfer data
5744
    var coords = new Float32Array(count * 2);
5745
    var colors = new Uint8Array(count * 3);
5746
    var coordsMap = context.coords, colorsMap = context.colors;
5747
    var pIndex = 0, cIndex = 0;
5748
    for (i = 0, ii = figures.length; i < ii; i++) {
5749
      var figure = figures[i], ps = figure.coords, cs = figure.colors;
5750
      switch (figure.type) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
5751
        case 'lattice':
5752
          var cols = figure.verticesPerRow;
5753
          rows = (ps.length / cols) | 0;
5754
          for (var row = 1; row < rows; row++) {
5755
            var offset = row * cols + 1;
5756
            for (var col = 1; col < cols; col++, offset++) {
5757
              coords[pIndex] = coordsMap[ps[offset - cols - 1]];
5758
              coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
5759
              coords[pIndex + 2] = coordsMap[ps[offset - cols]];
5760
              coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
5761
              coords[pIndex + 4] = coordsMap[ps[offset - 1]];
5762
              coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
5763
              colors[cIndex] = colorsMap[cs[offset - cols - 1]];
5764
              colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
5765
              colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
5766
              colors[cIndex + 3] = colorsMap[cs[offset - cols]];
5767
              colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
5768
              colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
5769
              colors[cIndex + 6] = colorsMap[cs[offset - 1]];
5770
              colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
5771
              colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
5772
5773
              coords[pIndex + 6] = coords[pIndex + 2];
5774
              coords[pIndex + 7] = coords[pIndex + 3];
5775
              coords[pIndex + 8] = coords[pIndex + 4];
5776
              coords[pIndex + 9] = coords[pIndex + 5];
5777
              coords[pIndex + 10] = coordsMap[ps[offset]];
5778
              coords[pIndex + 11] = coordsMap[ps[offset] + 1];
5779
              colors[cIndex + 9] = colors[cIndex + 3];
5780
              colors[cIndex + 10] = colors[cIndex + 4];
5781
              colors[cIndex + 11] = colors[cIndex + 5];
5782
              colors[cIndex + 12] = colors[cIndex + 6];
5783
              colors[cIndex + 13] = colors[cIndex + 7];
5784
              colors[cIndex + 14] = colors[cIndex + 8];
5785
              colors[cIndex + 15] = colorsMap[cs[offset]];
5786
              colors[cIndex + 16] = colorsMap[cs[offset] + 1];
5787
              colors[cIndex + 17] = colorsMap[cs[offset] + 2];
5788
              pIndex += 12;
5789
              cIndex += 18;
5790
            }
5791
          }
5792
          break;
5793
        case 'triangles':
5794
          for (var j = 0, jj = ps.length; j < jj; j++) {
5795
            coords[pIndex] = coordsMap[ps[j]];
5796
            coords[pIndex + 1] = coordsMap[ps[j] + 1];
5797
            colors[cIndex] = colorsMap[cs[i]];
5798
            colors[cIndex + 1] = colorsMap[cs[j] + 1];
5799
            colors[cIndex + 2] = colorsMap[cs[j] + 2];
5800
            pIndex += 2;
5801
            cIndex += 3;
5802
          }
5803
          break;
5804
      }
5805
    }
5806
5807
    // draw
5808
    if (backgroundColor) {
5809
      gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
5810
                    backgroundColor[2] / 255, 1.0);
5811
    } else {
5812
      gl.clearColor(0, 0, 0, 0);
5813
    }
5814
    gl.clear(gl.COLOR_BUFFER_BIT);
5815
5816
    var coordsBuffer = gl.createBuffer();
5817
    gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
5818
    gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
5819
    gl.enableVertexAttribArray(cache.positionLocation);
5820
    gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
5821
5822
    var colorsBuffer = gl.createBuffer();
5823
    gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
5824
    gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
5825
    gl.enableVertexAttribArray(cache.colorLocation);
5826
    gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
5827
                           0, 0);
5828
5829
    gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
5830
    gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
5831
5832
    gl.drawArrays(gl.TRIANGLES, 0, count);
5833
5834
    gl.flush();
5835
5836
    gl.deleteBuffer(coordsBuffer);
5837
    gl.deleteBuffer(colorsBuffer);
5838
5839
    return canvas;
5840
  }
5841
5842
  function cleanup() {
5843
    if (smaskCache && smaskCache.canvas) {
5844
      smaskCache.canvas.width = 0;
5845
      smaskCache.canvas.height = 0;
5846
    }
5847
    if (figuresCache && figuresCache.canvas) {
5848
      figuresCache.canvas.width = 0;
5849
      figuresCache.canvas.height = 0;
5850
    }
5851
    smaskCache = null;
5852
    figuresCache = null;
5853
  }
5854
5855
  return {
5856
    get isEnabled() {
5857
      if (PDFJS.disableWebGL) {
5858
        return false;
5859
      }
5860
      var enabled = false;
5861
      try {
5862
        generateGL();
5863
        enabled = !!currentGL;
5864
      } catch (e) { }
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
5865
      return shadow(this, 'isEnabled', enabled);
5866
    },
5867
    composeSMask: composeSMask,
5868
    drawFigures: drawFigures,
5869
    clear: cleanup
5870
  };
5871
})();
5872
5873
5874
var ShadingIRs = {};
5875
5876
ShadingIRs.RadialAxial = {
5877
  fromIR: function RadialAxial_fromIR(raw) {
5878
    var type = raw[1];
5879
    var colorStops = raw[2];
5880
    var p0 = raw[3];
5881
    var p1 = raw[4];
5882
    var r0 = raw[5];
5883
    var r1 = raw[6];
5884
    return {
5885
      type: 'Pattern',
5886
      getPattern: function RadialAxial_getPattern(ctx) {
5887
        var grad;
5888
        if (type === 'axial') {
5889
          grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
5890
        } else if (type === 'radial') {
5891
          grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
5892
        }
5893
5894
        for (var i = 0, ii = colorStops.length; i < ii; ++i) {
5895
          var c = colorStops[i];
5896
          grad.addColorStop(c[0], c[1]);
0 ignored issues
show
Bug introduced by
The variable grad does not seem to be initialized in case type === "radial" on line 5890 is false. Are you sure this can never be the case?
Loading history...
5897
        }
5898
        return grad;
5899
      }
5900
    };
5901
  }
5902
};
5903
5904
var createMeshCanvas = (function createMeshCanvasClosure() {
5905
  function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {
5906
    // Very basic Gouraud-shaded triangle rasterization algorithm.
5907
    var coords = context.coords, colors = context.colors;
5908
    var bytes = data.data, rowSize = data.width * 4;
5909
    var tmp;
5910
    if (coords[p1 + 1] > coords[p2 + 1]) {
5911
      tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
5912
    }
5913
    if (coords[p2 + 1] > coords[p3 + 1]) {
5914
      tmp = p2; p2 = p3; p3 = tmp; tmp = c2; c2 = c3; c3 = tmp;
5915
    }
5916
    if (coords[p1 + 1] > coords[p2 + 1]) {
5917
      tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
5918
    }
5919
    var x1 = (coords[p1] + context.offsetX) * context.scaleX;
5920
    var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;
5921
    var x2 = (coords[p2] + context.offsetX) * context.scaleX;
5922
    var y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY;
5923
    var x3 = (coords[p3] + context.offsetX) * context.scaleX;
5924
    var y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY;
5925
    if (y1 >= y3) {
5926
      return;
5927
    }
5928
    var c1r = colors[c1], c1g = colors[c1 + 1], c1b = colors[c1 + 2];
5929
    var c2r = colors[c2], c2g = colors[c2 + 1], c2b = colors[c2 + 2];
5930
    var c3r = colors[c3], c3g = colors[c3 + 1], c3b = colors[c3 + 2];
5931
5932
    var minY = Math.round(y1), maxY = Math.round(y3);
5933
    var xa, car, cag, cab;
5934
    var xb, cbr, cbg, cbb;
5935
    var k;
5936
    for (var y = minY; y <= maxY; y++) {
5937
      if (y < y2) {
5938
        k = y < y1 ? 0 : y1 === y2 ? 1 : (y1 - y) / (y1 - y2);
5939
        xa = x1 - (x1 - x2) * k;
5940
        car = c1r - (c1r - c2r) * k;
5941
        cag = c1g - (c1g - c2g) * k;
5942
        cab = c1b - (c1b - c2b) * k;
5943
      } else {
5944
        k = y > y3 ? 1 : y2 === y3 ? 0 : (y2 - y) / (y2 - y3);
5945
        xa = x2 - (x2 - x3) * k;
5946
        car = c2r - (c2r - c3r) * k;
5947
        cag = c2g - (c2g - c3g) * k;
5948
        cab = c2b - (c2b - c3b) * k;
5949
      }
5950
      k = y < y1 ? 0 : y > y3 ? 1 : (y1 - y) / (y1 - y3);
5951
      xb = x1 - (x1 - x3) * k;
5952
      cbr = c1r - (c1r - c3r) * k;
5953
      cbg = c1g - (c1g - c3g) * k;
5954
      cbb = c1b - (c1b - c3b) * k;
5955
      var x1_ = Math.round(Math.min(xa, xb));
5956
      var x2_ = Math.round(Math.max(xa, xb));
5957
      var j = rowSize * y + x1_ * 4;
5958
      for (var x = x1_; x <= x2_; x++) {
5959
        k = (xa - x) / (xa - xb);
5960
        k = k < 0 ? 0 : k > 1 ? 1 : k;
5961
        bytes[j++] = (car - (car - cbr) * k) | 0;
5962
        bytes[j++] = (cag - (cag - cbg) * k) | 0;
5963
        bytes[j++] = (cab - (cab - cbb) * k) | 0;
5964
        bytes[j++] = 255;
5965
      }
5966
    }
5967
  }
5968
5969
  function drawFigure(data, figure, context) {
5970
    var ps = figure.coords;
5971
    var cs = figure.colors;
5972
    var i, ii;
5973
    switch (figure.type) {
5974
      case 'lattice':
5975
        var verticesPerRow = figure.verticesPerRow;
5976
        var rows = Math.floor(ps.length / verticesPerRow) - 1;
5977
        var cols = verticesPerRow - 1;
5978
        for (i = 0; i < rows; i++) {
5979
          var q = i * verticesPerRow;
5980
          for (var j = 0; j < cols; j++, q++) {
5981
            drawTriangle(data, context,
5982
              ps[q], ps[q + 1], ps[q + verticesPerRow],
5983
              cs[q], cs[q + 1], cs[q + verticesPerRow]);
5984
            drawTriangle(data, context,
5985
              ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow],
5986
              cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]);
5987
          }
5988
        }
5989
        break;
5990
      case 'triangles':
5991
        for (i = 0, ii = ps.length; i < ii; i += 3) {
5992
          drawTriangle(data, context,
5993
            ps[i], ps[i + 1], ps[i + 2],
5994
            cs[i], cs[i + 1], cs[i + 2]);
5995
        }
5996
        break;
5997
      default:
5998
        error('illigal figure');
5999
        break;
6000
    }
6001
  }
6002
6003
  function createMeshCanvas(bounds, combinesScale, coords, colors, figures,
6004
                            backgroundColor) {
6005
    // we will increase scale on some weird factor to let antialiasing take
6006
    // care of "rough" edges
6007
    var EXPECTED_SCALE = 1.1;
6008
    // MAX_PATTERN_SIZE is used to avoid OOM situation.
6009
    var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
6010
6011
    var offsetX = Math.floor(bounds[0]);
6012
    var offsetY = Math.floor(bounds[1]);
6013
    var boundsWidth = Math.ceil(bounds[2]) - offsetX;
6014
    var boundsHeight = Math.ceil(bounds[3]) - offsetY;
6015
6016
    var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] *
6017
      EXPECTED_SCALE)), MAX_PATTERN_SIZE);
6018
    var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] *
6019
      EXPECTED_SCALE)), MAX_PATTERN_SIZE);
6020
    var scaleX = boundsWidth / width;
6021
    var scaleY = boundsHeight / height;
6022
6023
    var context = {
6024
      coords: coords,
6025
      colors: colors,
6026
      offsetX: -offsetX,
6027
      offsetY: -offsetY,
6028
      scaleX: 1 / scaleX,
6029
      scaleY: 1 / scaleY
6030
    };
6031
6032
    var canvas, tmpCanvas, i, ii;
6033
    if (WebGLUtils.isEnabled) {
6034
      canvas = WebGLUtils.drawFigures(width, height, backgroundColor,
6035
                                      figures, context);
6036
6037
      // https://bugzilla.mozilla.org/show_bug.cgi?id=972126
6038
      tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
6039
      tmpCanvas.context.drawImage(canvas, 0, 0);
6040
      canvas = tmpCanvas.canvas;
6041
    } else {
6042
      tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
6043
      var tmpCtx = tmpCanvas.context;
6044
6045
      var data = tmpCtx.createImageData(width, height);
6046
      if (backgroundColor) {
6047
        var bytes = data.data;
6048
        for (i = 0, ii = bytes.length; i < ii; i += 4) {
6049
          bytes[i] = backgroundColor[0];
6050
          bytes[i + 1] = backgroundColor[1];
6051
          bytes[i + 2] = backgroundColor[2];
6052
          bytes[i + 3] = 255;
6053
        }
6054
      }
6055
      for (i = 0; i < figures.length; i++) {
6056
        drawFigure(data, figures[i], context);
6057
      }
6058
      tmpCtx.putImageData(data, 0, 0);
6059
      canvas = tmpCanvas.canvas;
6060
    }
6061
6062
    return {canvas: canvas, offsetX: offsetX, offsetY: offsetY,
6063
            scaleX: scaleX, scaleY: scaleY};
6064
  }
6065
  return createMeshCanvas;
6066
})();
6067
6068
ShadingIRs.Mesh = {
6069
  fromIR: function Mesh_fromIR(raw) {
6070
    //var type = raw[1];
6071
    var coords = raw[2];
6072
    var colors = raw[3];
6073
    var figures = raw[4];
6074
    var bounds = raw[5];
6075
    var matrix = raw[6];
6076
    //var bbox = raw[7];
6077
    var background = raw[8];
6078
    return {
6079
      type: 'Pattern',
6080
      getPattern: function Mesh_getPattern(ctx, owner, shadingFill) {
6081
        var scale;
6082
        if (shadingFill) {
6083
          scale = Util.singularValueDecompose2dScale(ctx.mozCurrentTransform);
6084
        } else {
6085
          // Obtain scale from matrix and current transformation matrix.
6086
          scale = Util.singularValueDecompose2dScale(owner.baseTransform);
6087
          if (matrix) {
6088
            var matrixScale = Util.singularValueDecompose2dScale(matrix);
6089
            scale = [scale[0] * matrixScale[0],
6090
                     scale[1] * matrixScale[1]];
6091
          }
6092
        }
6093
6094
6095
        // Rasterizing on the main thread since sending/queue large canvases
6096
        // might cause OOM.
6097
        var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords,
6098
          colors, figures, shadingFill ? null : background);
6099
6100
        if (!shadingFill) {
6101
          ctx.setTransform.apply(ctx, owner.baseTransform);
6102
          if (matrix) {
6103
            ctx.transform.apply(ctx, matrix);
6104
          }
6105
        }
6106
6107
        ctx.translate(temporaryPatternCanvas.offsetX,
6108
                      temporaryPatternCanvas.offsetY);
6109
        ctx.scale(temporaryPatternCanvas.scaleX,
6110
                  temporaryPatternCanvas.scaleY);
6111
6112
        return ctx.createPattern(temporaryPatternCanvas.canvas, 'no-repeat');
6113
      }
6114
    };
6115
  }
6116
};
6117
6118
ShadingIRs.Dummy = {
6119
  fromIR: function Dummy_fromIR() {
6120
    return {
6121
      type: 'Pattern',
6122
      getPattern: function Dummy_fromIR_getPattern() {
6123
        return 'hotpink';
6124
      }
6125
    };
6126
  }
6127
};
6128
6129
function getShadingPatternFromIR(raw) {
6130
  var shadingIR = ShadingIRs[raw[0]];
6131
  if (!shadingIR) {
6132
    error('Unknown IR type: ' + raw[0]);
6133
  }
6134
  return shadingIR.fromIR(raw);
6135
}
6136
6137
var TilingPattern = (function TilingPatternClosure() {
6138
  var PaintType = {
0 ignored issues
show
Unused Code introduced by
The variable PaintType seems to be never used. Consider removing it.
Loading history...
6139
    COLORED: 1,
6140
    UNCOLORED: 2
6141
  };
6142
6143
  var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
6144
6145
  function TilingPattern(IR, color, ctx, objs, commonObjs, baseTransform) {
6146
    this.operatorList = IR[2];
6147
    this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
6148
    this.bbox = IR[4];
6149
    this.xstep = IR[5];
6150
    this.ystep = IR[6];
6151
    this.paintType = IR[7];
6152
    this.tilingType = IR[8];
6153
    this.color = color;
6154
    this.objs = objs;
6155
    this.commonObjs = commonObjs;
6156
    this.baseTransform = baseTransform;
6157
    this.type = 'Pattern';
6158
    this.ctx = ctx;
6159
  }
6160
6161
  TilingPattern.prototype = {
6162
    createPatternCanvas: function TilinPattern_createPatternCanvas(owner) {
6163
      var operatorList = this.operatorList;
6164
      var bbox = this.bbox;
6165
      var xstep = this.xstep;
6166
      var ystep = this.ystep;
6167
      var paintType = this.paintType;
6168
      var tilingType = this.tilingType;
6169
      var color = this.color;
6170
      var objs = this.objs;
6171
      var commonObjs = this.commonObjs;
6172
6173
      info('TilingType: ' + tilingType);
6174
6175
      var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
6176
6177
      var topLeft = [x0, y0];
6178
      // we want the canvas to be as large as the step size
6179
      var botRight = [x0 + xstep, y0 + ystep];
6180
6181
      var width = botRight[0] - topLeft[0];
6182
      var height = botRight[1] - topLeft[1];
6183
6184
      // Obtain scale from matrix and current transformation matrix.
6185
      var matrixScale = Util.singularValueDecompose2dScale(this.matrix);
6186
      var curMatrixScale = Util.singularValueDecompose2dScale(
6187
        this.baseTransform);
6188
      var combinedScale = [matrixScale[0] * curMatrixScale[0],
6189
        matrixScale[1] * curMatrixScale[1]];
6190
6191
      // MAX_PATTERN_SIZE is used to avoid OOM situation.
6192
      // Use width and height values that are as close as possible to the end
6193
      // result when the pattern is used. Too low value makes the pattern look
6194
      // blurry. Too large value makes it look too crispy.
6195
      width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])),
6196
        MAX_PATTERN_SIZE);
6197
6198
      height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),
6199
        MAX_PATTERN_SIZE);
6200
6201
      var tmpCanvas = CachedCanvases.getCanvas('pattern', width, height, true);
6202
      var tmpCtx = tmpCanvas.context;
6203
      var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
6204
      graphics.groupLevel = owner.groupLevel;
6205
6206
      this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
6207
6208
      this.setScale(width, height, xstep, ystep);
6209
      this.transformToScale(graphics);
6210
6211
      // transform coordinates to pattern space
6212
      var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
6213
      graphics.transform.apply(graphics, tmpTranslate);
6214
6215
      this.clipBbox(graphics, bbox, x0, y0, x1, y1);
6216
6217
      graphics.executeOperatorList(operatorList);
6218
      return tmpCanvas.canvas;
6219
    },
6220
6221
    setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
6222
      this.scale = [width / xstep, height / ystep];
6223
    },
6224
6225
    transformToScale: function TilingPattern_transformToScale(graphics) {
6226
      var scale = this.scale;
6227
      var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
6228
      graphics.transform.apply(graphics, tmpScale);
6229
    },
6230
6231
    scaleToContext: function TilingPattern_scaleToContext() {
6232
      var scale = this.scale;
6233
      this.ctx.scale(1 / scale[0], 1 / scale[1]);
6234
    },
6235
6236
    clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) {
6237
      if (bbox && isArray(bbox) && bbox.length === 4) {
6238
        var bboxWidth = x1 - x0;
6239
        var bboxHeight = y1 - y0;
6240
        graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight);
6241
        graphics.clip();
6242
        graphics.endPath();
6243
      }
6244
    },
6245
6246
    setFillAndStrokeStyleToContext:
6247
      function setFillAndStrokeStyleToContext(context, paintType, color) {
6248
        switch (paintType) {
6249
          case PaintType.COLORED:
0 ignored issues
show
Bug introduced by
The variable PaintType seems to be never declared. If this is a global, consider adding a /** global: PaintType */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6250
            var ctx = this.ctx;
6251
            context.fillStyle = ctx.fillStyle;
6252
            context.strokeStyle = ctx.strokeStyle;
6253
            break;
6254
          case PaintType.UNCOLORED:
6255
            var cssColor = Util.makeCssRgb(color[0], color[1], color[2]);
6256
            context.fillStyle = cssColor;
6257
            context.strokeStyle = cssColor;
6258
            break;
6259
          default:
6260
            error('Unsupported paint type: ' + paintType);
6261
        }
6262
      },
6263
6264
    getPattern: function TilingPattern_getPattern(ctx, owner) {
6265
      var temporaryPatternCanvas = this.createPatternCanvas(owner);
6266
6267
      ctx = this.ctx;
6268
      ctx.setTransform.apply(ctx, this.baseTransform);
6269
      ctx.transform.apply(ctx, this.matrix);
6270
      this.scaleToContext();
6271
6272
      return ctx.createPattern(temporaryPatternCanvas, 'repeat');
6273
    }
6274
  };
6275
6276
  return TilingPattern;
6277
})();
6278
6279
6280
PDFJS.disableFontFace = false;
6281
6282
var FontLoader = {
6283
  insertRule: function fontLoaderInsertRule(rule) {
6284
    var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
6285
    if (!styleElement) {
6286
      styleElement = document.createElement('style');
6287
      styleElement.id = 'PDFJS_FONT_STYLE_TAG';
6288
      document.documentElement.getElementsByTagName('head')[0].appendChild(
6289
        styleElement);
6290
    }
6291
6292
    var styleSheet = styleElement.sheet;
6293
    styleSheet.insertRule(rule, styleSheet.cssRules.length);
6294
  },
6295
6296
  clear: function fontLoaderClear() {
6297
    var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
6298
    if (styleElement) {
6299
      styleElement.parentNode.removeChild(styleElement);
6300
    }
6301
//#if !(MOZCENTRAL)
6302
    this.nativeFontFaces.forEach(function(nativeFontFace) {
6303
      document.fonts.delete(nativeFontFace);
6304
    });
6305
    this.nativeFontFaces.length = 0;
6306
//#endif
6307
  },
6308
//#if !(MOZCENTRAL)
6309
  get loadTestFont() {
6310
    // This is a CFF font with 1 glyph for '.' that fills its entire width and
6311
    // height.
6312
    return shadow(this, 'loadTestFont', atob(
6313
      'T1RUTwALAIAAAwAwQ0ZGIDHtZg4AAAOYAAAAgUZGVE1lkzZwAAAEHAAAABxHREVGABQAFQ' +
6314
      'AABDgAAAAeT1MvMlYNYwkAAAEgAAAAYGNtYXABDQLUAAACNAAAAUJoZWFk/xVFDQAAALwA' +
6315
      'AAA2aGhlYQdkA+oAAAD0AAAAJGhtdHgD6AAAAAAEWAAAAAZtYXhwAAJQAAAAARgAAAAGbm' +
6316
      'FtZVjmdH4AAAGAAAAAsXBvc3T/hgAzAAADeAAAACAAAQAAAAEAALZRFsRfDzz1AAsD6AAA' +
6317
      'AADOBOTLAAAAAM4KHDwAAAAAA+gDIQAAAAgAAgAAAAAAAAABAAADIQAAAFoD6AAAAAAD6A' +
6318
      'ABAAAAAAAAAAAAAAAAAAAAAQAAUAAAAgAAAAQD6AH0AAUAAAKKArwAAACMAooCvAAAAeAA' +
6319
      'MQECAAACAAYJAAAAAAAAAAAAAQAAAAAAAAAAAAAAAFBmRWQAwAAuAC4DIP84AFoDIQAAAA' +
6320
      'AAAQAAAAAAAAAAACAAIAABAAAADgCuAAEAAAAAAAAAAQAAAAEAAAAAAAEAAQAAAAEAAAAA' +
6321
      'AAIAAQAAAAEAAAAAAAMAAQAAAAEAAAAAAAQAAQAAAAEAAAAAAAUAAQAAAAEAAAAAAAYAAQ' +
6322
      'AAAAMAAQQJAAAAAgABAAMAAQQJAAEAAgABAAMAAQQJAAIAAgABAAMAAQQJAAMAAgABAAMA' +
6323
      'AQQJAAQAAgABAAMAAQQJAAUAAgABAAMAAQQJAAYAAgABWABYAAAAAAAAAwAAAAMAAAAcAA' +
6324
      'EAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAAAC7//wAAAC7////TAAEAAAAAAAABBgAA' +
6325
      'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAA' +
6326
      'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
6327
      'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
6328
      'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' +
6329
      'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA' +
6330
      'AAAAD/gwAyAAAAAQAAAAAAAAAAAAAAAAAAAAABAAQEAAEBAQJYAAEBASH4DwD4GwHEAvgc' +
6331
      'A/gXBIwMAYuL+nz5tQXkD5j3CBLnEQACAQEBIVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF' +
6332
      'hYWFhYWFhYAAABAQAADwACAQEEE/t3Dov6fAH6fAT+fPp8+nwHDosMCvm1Cvm1DAz6fBQA' +
6333
      'AAAAAAABAAAAAMmJbzEAAAAAzgTjFQAAAADOBOQpAAEAAAAAAAAADAAUAAQAAAABAAAAAg' +
6334
      'ABAAAAAAAAAAAD6AAAAAAAAA=='
6335
    ));
6336
  },
6337
6338
  loadTestFontId: 0,
6339
6340
  loadingContext: {
6341
    requests: [],
6342
    nextRequestId: 0
6343
  },
6344
6345
  isSyncFontLoadingSupported: (function detectSyncFontLoadingSupport() {
6346
    if (isWorker) {
6347
      return false;
6348
    }
6349
6350
    // User agent string sniffing is bad, but there is no reliable way to tell
6351
    // if font is fully loaded and ready to be used with canvas.
6352
    var userAgent = window.navigator.userAgent;
6353
    var m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(userAgent);
6354
    if (m && m[1] >= 14) {
6355
      return true;
6356
    }
6357
    // TODO other browsers
6358
    if (userAgent === 'node') {
6359
      return true;
6360
    }
6361
    return false;
6362
  })(),
6363
6364
  nativeFontFaces: [],
6365
6366
  isFontLoadingAPISupported: (!isWorker && typeof document !== 'undefined' &&
6367
                              !!document.fonts),
6368
6369
  addNativeFontFace: function fontLoader_addNativeFontFace(nativeFontFace) {
6370
    this.nativeFontFaces.push(nativeFontFace);
6371
    document.fonts.add(nativeFontFace);
6372
  },
6373
6374
  bind: function fontLoaderBind(fonts, callback) {
6375
    assert(!isWorker, 'bind() shall be called from main thread');
6376
6377
    var rules = [];
6378
    var fontsToLoad = [];
6379
    var fontLoadPromises = [];
6380
    for (var i = 0, ii = fonts.length; i < ii; i++) {
6381
      var font = fonts[i];
6382
6383
      // Add the font to the DOM only once or skip if the font
6384
      // is already loaded.
6385
      if (font.attached || font.loading === false) {
6386
        continue;
6387
      }
6388
      font.attached = true;
6389
6390
      if (this.isFontLoadingAPISupported) {
6391
        var nativeFontFace = font.createNativeFontFace();
6392
        if (nativeFontFace) {
6393
          fontLoadPromises.push(nativeFontFace.loaded);
6394
        }
6395
      } else {
6396
        var rule = font.bindDOM();
6397
        if (rule) {
6398
          rules.push(rule);
6399
          fontsToLoad.push(font);
6400
        }
6401
      }
6402
    }
6403
6404
    var request = FontLoader.queueLoadingCallback(callback);
6405
    if (this.isFontLoadingAPISupported) {
6406
      Promise.all(fontsToLoad).then(function() {
6407
        request.complete();
6408
      });
6409
    } else if (rules.length > 0 && !this.isSyncFontLoadingSupported) {
6410
      FontLoader.prepareFontLoadEvent(rules, fontsToLoad, request);
6411
    } else {
6412
      request.complete();
6413
    }
6414
  },
6415
6416
  queueLoadingCallback: function FontLoader_queueLoadingCallback(callback) {
6417
    function LoadLoader_completeRequest() {
6418
      assert(!request.end, 'completeRequest() cannot be called twice');
6419
      request.end = Date.now();
6420
6421
      // sending all completed requests in order how they were queued
6422
      while (context.requests.length > 0 && context.requests[0].end) {
6423
        var otherRequest = context.requests.shift();
6424
        setTimeout(otherRequest.callback, 0);
6425
      }
6426
    }
6427
6428
    var context = FontLoader.loadingContext;
6429
    var requestId = 'pdfjs-font-loading-' + (context.nextRequestId++);
6430
    var request = {
6431
      id: requestId,
6432
      complete: LoadLoader_completeRequest,
6433
      callback: callback,
6434
      started: Date.now()
6435
    };
6436
    context.requests.push(request);
6437
    return request;
6438
  },
6439
6440
  prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules,
6441
                                                                fonts,
6442
                                                                request) {
6443
      /** Hack begin */
6444
      // There's currently no event when a font has finished downloading so the
6445
      // following code is a dirty hack to 'guess' when a font is
6446
      // ready. It's assumed fonts are loaded in order, so add a known test
6447
      // font after the desired fonts and then test for the loading of that
6448
      // test font.
6449
6450
      function int32(data, offset) {
6451
        return (data.charCodeAt(offset) << 24) |
6452
               (data.charCodeAt(offset + 1) << 16) |
6453
               (data.charCodeAt(offset + 2) << 8) |
6454
               (data.charCodeAt(offset + 3) & 0xff);
6455
      }
6456
6457
      function spliceString(s, offset, remove, insert) {
6458
        var chunk1 = s.substr(0, offset);
6459
        var chunk2 = s.substr(offset + remove);
6460
        return chunk1 + insert + chunk2;
6461
      }
6462
6463
      var i, ii;
6464
6465
      var canvas = document.createElement('canvas');
6466
      canvas.width = 1;
6467
      canvas.height = 1;
6468
      var ctx = canvas.getContext('2d');
6469
6470
      var called = 0;
6471
      function isFontReady(name, callback) {
6472
        called++;
6473
        // With setTimeout clamping this gives the font ~100ms to load.
6474
        if(called > 30) {
6475
          warn('Load test font never loaded.');
6476
          callback();
6477
          return;
6478
        }
6479
        ctx.font = '30px ' + name;
6480
        ctx.fillText('.', 0, 20);
6481
        var imageData = ctx.getImageData(0, 0, 1, 1);
6482
        if (imageData.data[3] > 0) {
6483
          callback();
6484
          return;
6485
        }
6486
        setTimeout(isFontReady.bind(null, name, callback));
0 ignored issues
show
Unused Code introduced by
The call to bind does not seem necessary since the function isFontReady declared on line 6471 does not use this.
Loading history...
6487
      }
6488
6489
      var loadTestFontId = 'lt' + Date.now() + this.loadTestFontId++;
6490
      // Chromium seems to cache fonts based on a hash of the actual font data,
6491
      // so the font must be modified for each load test else it will appear to
6492
      // be loaded already.
6493
      // TODO: This could maybe be made faster by avoiding the btoa of the full
6494
      // font by splitting it in chunks before hand and padding the font id.
6495
      var data = this.loadTestFont;
6496
      var COMMENT_OFFSET = 976; // has to be on 4 byte boundary (for checksum)
6497
      data = spliceString(data, COMMENT_OFFSET, loadTestFontId.length,
6498
                          loadTestFontId);
6499
      // CFF checksum is important for IE, adjusting it
6500
      var CFF_CHECKSUM_OFFSET = 16;
6501
      var XXXX_VALUE = 0x58585858; // the "comment" filled with 'X'
6502
      var checksum = int32(data, CFF_CHECKSUM_OFFSET);
6503
      for (i = 0, ii = loadTestFontId.length - 3; i < ii; i += 4) {
6504
        checksum = (checksum - XXXX_VALUE + int32(loadTestFontId, i)) | 0;
6505
      }
6506
      if (i < loadTestFontId.length) { // align to 4 bytes boundary
6507
        checksum = (checksum - XXXX_VALUE +
6508
                    int32(loadTestFontId + 'XXX', i)) | 0;
6509
      }
6510
      data = spliceString(data, CFF_CHECKSUM_OFFSET, 4, string32(checksum));
6511
6512
      var url = 'url(data:font/opentype;base64,' + btoa(data) + ');';
6513
      var rule = '@font-face { font-family:"' + loadTestFontId + '";src:' +
6514
                 url + '}';
6515
      FontLoader.insertRule(rule);
6516
6517
      var names = [];
6518
      for (i = 0, ii = fonts.length; i < ii; i++) {
6519
        names.push(fonts[i].loadedName);
6520
      }
6521
      names.push(loadTestFontId);
6522
6523
      var div = document.createElement('div');
6524
      div.setAttribute('style',
6525
                       'visibility: hidden;' +
6526
                       'width: 10px; height: 10px;' +
6527
                       'position: absolute; top: 0px; left: 0px;');
6528
      for (i = 0, ii = names.length; i < ii; ++i) {
6529
        var span = document.createElement('span');
6530
        span.textContent = 'Hi';
6531
        span.style.fontFamily = names[i];
6532
        div.appendChild(span);
6533
      }
6534
      document.body.appendChild(div);
6535
6536
      isFontReady(loadTestFontId, function() {
6537
        document.body.removeChild(div);
6538
        request.complete();
6539
      });
6540
      /** Hack end */
6541
  }
6542
//#else
6543
//bind: function fontLoaderBind(fonts, callback) {
6544
//  assert(!isWorker, 'bind() shall be called from main thread');
6545
//
6546
//  for (var i = 0, ii = fonts.length; i < ii; i++) {
6547
//    var font = fonts[i];
6548
//    if (font.attached) {
6549
//      continue;
6550
//    }
6551
//
6552
//    font.attached = true;
6553
//    font.bindDOM()
6554
//  }
6555
//
6556
//  setTimeout(callback);
6557
//}
6558
//#endif
6559
};
6560
6561
var FontFaceObject = (function FontFaceObjectClosure() {
6562
  function FontFaceObject(name, file, properties) {
0 ignored issues
show
Unused Code introduced by
The parameter name is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter properties is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter file is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
6563
    this.compiledGlyphs = {};
6564
    if (arguments.length === 1) {
6565
      // importing translated data
6566
      var data = arguments[0];
6567
      for (var i in data) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
6568
        this[i] = data[i];
6569
      }
6570
      return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
6571
    }
6572
  }
6573
  FontFaceObject.prototype = {
6574
//#if !(MOZCENTRAL)
6575
    createNativeFontFace: function FontFaceObject_createNativeFontFace() {
6576
      if (!this.data) {
6577
        return null;
6578
      }
6579
6580
      if (PDFJS.disableFontFace) {
6581
        this.disableFontFace = true;
6582
        return null;
6583
      }
6584
6585
      var nativeFontFace = new FontFace(this.loadedName, this.data, {});
0 ignored issues
show
Bug introduced by
The variable FontFace seems to be never declared. If this is a global, consider adding a /** global: FontFace */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6586
6587
      FontLoader.addNativeFontFace(nativeFontFace);
6588
6589
      if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
6590
          globalScope['FontInspector'].enabled) {
6591
        globalScope['FontInspector'].fontAdded(this);
6592
      }
6593
      return nativeFontFace;
6594
    },
6595
//#endif
6596
6597
    bindDOM: function FontFaceObject_bindDOM() {
6598
      if (!this.data) {
6599
        return null;
6600
      }
6601
6602
      if (PDFJS.disableFontFace) {
6603
        this.disableFontFace = true;
6604
        return null;
6605
      }
6606
6607
      var data = bytesToString(new Uint8Array(this.data));
6608
      var fontName = this.loadedName;
6609
6610
      // Add the font-face rule to the document
6611
      var url = ('url(data:' + this.mimetype + ';base64,' +
6612
                 window.btoa(data) + ');');
6613
      var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}';
6614
      FontLoader.insertRule(rule);
6615
6616
      if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
6617
          globalScope['FontInspector'].enabled) {
6618
        globalScope['FontInspector'].fontAdded(this, url);
6619
      }
6620
6621
      return rule;
6622
    },
6623
6624
    getPathGenerator: function FontLoader_getPathGenerator(objs, character) {
6625
      if (!(character in this.compiledGlyphs)) {
6626
        var js = objs.get(this.loadedName + '_path_' + character);
6627
        /*jshint -W054 */
6628
        this.compiledGlyphs[character] = new Function('c', 'size', js);
0 ignored issues
show
Performance Best Practice introduced by
Using new Function() to create a function is slow and difficult to debug. Such functions do not create a closure. Consider using another way to define your function.
Loading history...
6629
      }
6630
      return this.compiledGlyphs[character];
6631
    }
6632
  };
6633
  return FontFaceObject;
6634
})();
6635
6636
6637
var ANNOT_MIN_SIZE = 10; // px
6638
6639
var AnnotationUtils = (function AnnotationUtilsClosure() {
6640
  // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont()
6641
  function setTextStyles(element, item, fontObj) {
6642
6643
    var style = element.style;
6644
    style.fontSize = item.fontSize + 'px';
6645
    style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
6646
6647
    if (!fontObj) {
6648
      return;
6649
    }
6650
6651
    style.fontWeight = fontObj.black ?
6652
      (fontObj.bold ? 'bolder' : 'bold') :
6653
      (fontObj.bold ? 'bold' : 'normal');
6654
    style.fontStyle = fontObj.italic ? 'italic' : 'normal';
6655
6656
    var fontName = fontObj.loadedName;
6657
    var fontFamily = fontName ? '"' + fontName + '", ' : '';
6658
    // Use a reasonable default font if the font doesn't specify a fallback
6659
    var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
6660
    style.fontFamily = fontFamily + fallbackName;
6661
  }
6662
6663
  function initContainer(item, drawBorder) {
6664
    var container = document.createElement('section');
6665
    var cstyle = container.style;
6666
    var width = item.rect[2] - item.rect[0];
6667
    var height = item.rect[3] - item.rect[1];
6668
6669
    var bWidth = item.borderWidth || 0;
6670
    if (bWidth) {
6671
      width = width - 2 * bWidth;
6672
      height = height - 2 * bWidth;
6673
      cstyle.borderWidth = bWidth + 'px';
6674
      var color = item.color;
6675
      if (drawBorder && color) {
6676
        cstyle.borderStyle = 'solid';
6677
        cstyle.borderColor = Util.makeCssRgb(Math.round(color[0] * 255),
6678
                                             Math.round(color[1] * 255),
6679
                                             Math.round(color[2] * 255));
6680
      }
6681
    }
6682
    cstyle.width = width + 'px';
6683
    cstyle.height = height + 'px';
6684
    return container;
6685
  }
6686
6687
  function getHtmlElementForTextWidgetAnnotation(item, commonObjs) {
6688
    var element = document.createElement('div');
6689
    var width = item.rect[2] - item.rect[0];
6690
    var height = item.rect[3] - item.rect[1];
6691
    element.style.width = width + 'px';
6692
    element.style.height = height + 'px';
6693
    element.style.display = 'table';
6694
6695
    var content = document.createElement('div');
6696
    content.textContent = item.fieldValue;
6697
    var textAlignment = item.textAlignment;
6698
    content.style.textAlign = ['left', 'center', 'right'][textAlignment];
6699
    content.style.verticalAlign = 'middle';
6700
    content.style.display = 'table-cell';
6701
6702
    var fontObj = item.fontRefName ?
6703
      commonObjs.getData(item.fontRefName) : null;
6704
    setTextStyles(content, item, fontObj);
6705
6706
    element.appendChild(content);
6707
6708
    return element;
6709
  }
6710
6711
  function getHtmlElementForTextAnnotation(item) {
6712
    var rect = item.rect;
6713
6714
    // sanity check because of OOo-generated PDFs
6715
    if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
6716
      rect[3] = rect[1] + ANNOT_MIN_SIZE;
6717
    }
6718
    if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
6719
      rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
6720
    }
6721
6722
    var container = initContainer(item, false);
6723
    container.className = 'annotText';
6724
6725
    var image  = document.createElement('img');
6726
    image.style.height = container.style.height;
6727
    image.style.width = container.style.width;
6728
    var iconName = item.name;
6729
    image.src = PDFJS.imageResourcesPath + 'annotation-' +
6730
      iconName.toLowerCase() + '.svg';
6731
    image.alt = '[{{type}} Annotation]';
6732
    image.dataset.l10nId = 'text_annotation_type';
6733
    image.dataset.l10nArgs = JSON.stringify({type: iconName});
6734
6735
    var contentWrapper = document.createElement('div');
6736
    contentWrapper.className = 'annotTextContentWrapper';
6737
    contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px';
6738
    contentWrapper.style.top = '-10px';
6739
6740
    var content = document.createElement('div');
6741
    content.className = 'annotTextContent';
6742
    content.setAttribute('hidden', true);
6743
6744
    var i, ii;
6745
    if (item.hasBgColor) {
6746
      var color = item.color;
6747
6748
      // Enlighten the color (70%)
6749
      var BACKGROUND_ENLIGHT = 0.7;
6750
      var r = BACKGROUND_ENLIGHT * (1.0 - color[0]) + color[0];
6751
      var g = BACKGROUND_ENLIGHT * (1.0 - color[1]) + color[1];
6752
      var b = BACKGROUND_ENLIGHT * (1.0 - color[2]) + color[2];
6753
      content.style.backgroundColor = Util.makeCssRgb((r * 255) | 0,
6754
                                                      (g * 255) | 0,
6755
                                                      (b * 255) | 0);
6756
    }
6757
6758
    var title = document.createElement('h1');
6759
    var text = document.createElement('p');
6760
    title.textContent = item.title;
6761
6762
    if (!item.content && !item.title) {
6763
      content.setAttribute('hidden', true);
6764
    } else {
6765
      var e = document.createElement('span');
6766
      var lines = item.content.split(/(?:\r\n?|\n)/);
6767
      for (i = 0, ii = lines.length; i < ii; ++i) {
6768
        var line = lines[i];
6769
        e.appendChild(document.createTextNode(line));
6770
        if (i < (ii - 1)) {
6771
          e.appendChild(document.createElement('br'));
6772
        }
6773
      }
6774
      text.appendChild(e);
6775
6776
      var pinned = false;
6777
6778
      var showAnnotation = function showAnnotation(pin) {
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable showAnnotation already seems to be declared on line 6778. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
6779
        if (pin) {
6780
          pinned = true;
6781
        }
6782
        if (content.hasAttribute('hidden')) {
6783
          container.style.zIndex += 1;
6784
          content.removeAttribute('hidden');
6785
        }
6786
      };
6787
6788
      var hideAnnotation = function hideAnnotation(unpin) {
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable hideAnnotation already seems to be declared on line 6788. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
6789
        if (unpin) {
6790
          pinned = false;
6791
        }
6792
        if (!content.hasAttribute('hidden') && !pinned) {
6793
          container.style.zIndex -= 1;
6794
          content.setAttribute('hidden', true);
6795
        }
6796
      };
6797
6798
      var toggleAnnotation = function toggleAnnotation() {
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable toggleAnnotation already seems to be declared on line 6798. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
6799
        if (pinned) {
6800
          hideAnnotation(true);
6801
        } else {
6802
          showAnnotation(true);
6803
        }
6804
      };
6805
6806
      image.addEventListener('click', function image_clickHandler() {
6807
        toggleAnnotation();
6808
      }, false);
6809
      image.addEventListener('mouseover', function image_mouseOverHandler() {
6810
        showAnnotation();
6811
      }, false);
6812
      image.addEventListener('mouseout', function image_mouseOutHandler() {
6813
        hideAnnotation();
6814
      }, false);
6815
6816
      content.addEventListener('click', function content_clickHandler() {
6817
        hideAnnotation(true);
6818
      }, false);
6819
    }
6820
6821
    content.appendChild(title);
6822
    content.appendChild(text);
6823
    contentWrapper.appendChild(content);
6824
    container.appendChild(image);
6825
    container.appendChild(contentWrapper);
6826
6827
    return container;
6828
  }
6829
6830
  function getHtmlElementForLinkAnnotation(item) {
6831
    var container = initContainer(item, true);
6832
    container.className = 'annotLink';
6833
6834
    var link = document.createElement('a');
6835
    link.href = link.title = item.url || '';
6836
    if (item.url && PDFJS.openExternalLinksInNewWindow) {
6837
      link.target = '_blank';
6838
    }
6839
6840
    container.appendChild(link);
6841
6842
    return container;
6843
  }
6844
6845
  function getHtmlElement(data, objs) {
6846
    switch (data.annotationType) {
6847
      case AnnotationType.WIDGET:
0 ignored issues
show
Bug introduced by
The variable AnnotationType seems to be never declared. If this is a global, consider adding a /** global: AnnotationType */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6848
        return getHtmlElementForTextWidgetAnnotation(data, objs);
6849
      case AnnotationType.TEXT:
6850
        return getHtmlElementForTextAnnotation(data);
6851
      case AnnotationType.LINK:
6852
        return getHtmlElementForLinkAnnotation(data);
6853
      default:
6854
        throw new Error('Unsupported annotationType: ' + data.annotationType);
6855
    }
6856
  }
6857
6858
  return {
6859
    getHtmlElement: getHtmlElement
6860
  };
6861
})();
6862
PDFJS.AnnotationUtils = AnnotationUtils;
6863
6864
6865
//#if (GENERIC || SINGLE_FILE)
6866
var SVG_DEFAULTS = {
6867
  fontStyle: 'normal',
6868
  fontWeight: 'normal',
6869
  fillColor: '#000000'
6870
};
6871
6872
var convertImgDataToPng = (function convertImgDataToPngClosure() {
6873
  var PNG_HEADER =
6874
    new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
6875
6876
  var CHUNK_WRAPPER_SIZE = 12;
6877
6878
  var crcTable = new Int32Array(256);
6879
  for (var i = 0; i < 256; i++) {
6880
    var c = i;
6881
    for (var h = 0; h < 8; h++) {
6882
      if (c & 1) {
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
6883
        c = 0xedB88320 ^ ((c >> 1) & 0x7fffffff);
6884
      } else {
6885
        c = (c >> 1) & 0x7fffffff;
6886
      }
6887
    }
6888
    crcTable[i] = c;
6889
  }
6890
6891
  function crc32(data, start, end) {
6892
    var crc = -1;
6893
    for (var i = start; i < end; i++) {
6894
      var a = (crc ^ data[i]) & 0xff;
6895
      var b = crcTable[a];
6896
      crc = (crc >>> 8) ^ b;
6897
    }
6898
    return crc ^ -1;
6899
  }
6900
6901
  function writePngChunk(type, body, data, offset) {
6902
    var p = offset;
6903
    var len = body.length;
6904
6905
    data[p] = len >> 24 & 0xff;
6906
    data[p + 1] = len >> 16 & 0xff;
6907
    data[p + 2] = len >> 8 & 0xff;
6908
    data[p + 3] = len & 0xff;
6909
    p += 4;
6910
6911
    data[p] = type.charCodeAt(0) & 0xff;
6912
    data[p + 1] = type.charCodeAt(1) & 0xff;
6913
    data[p + 2] = type.charCodeAt(2) & 0xff;
6914
    data[p + 3] = type.charCodeAt(3) & 0xff;
6915
    p += 4;
6916
6917
    data.set(body, p);
6918
    p += body.length;
6919
6920
    var crc = crc32(data, offset + 4, p);
6921
6922
    data[p] = crc >> 24 & 0xff;
6923
    data[p + 1] = crc >> 16 & 0xff;
6924
    data[p + 2] = crc >> 8 & 0xff;
6925
    data[p + 3] = crc & 0xff;
6926
  }
6927
6928
  function adler32(data, start, end) {
6929
    var a = 1;
6930
    var b = 0;
6931
    for (var i = start; i < end; ++i) {
6932
      a = (a + (data[i] & 0xff)) % 65521;
6933
      b = (b + a) % 65521;
6934
    }
6935
    return (b << 16) | a;
6936
  }
6937
6938
  function encode(imgData, kind) {
6939
    var width = imgData.width;
6940
    var height = imgData.height;
6941
    var bitDepth, colorType, lineSize;
6942
    var bytes = imgData.data;
6943
6944
    switch (kind) {
6945
      case ImageKind.GRAYSCALE_1BPP:
0 ignored issues
show
Bug introduced by
The variable ImageKind seems to be never declared. If this is a global, consider adding a /** global: ImageKind */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6946
        colorType = 0;
6947
        bitDepth = 1;
6948
        lineSize = (width + 7) >> 3;
6949
        break;
6950
      case ImageKind.RGB_24BPP:
6951
        colorType = 2;
6952
        bitDepth = 8;
6953
        lineSize = width * 3;
6954
        break;
6955
      case ImageKind.RGBA_32BPP:
6956
        colorType = 6;
6957
        bitDepth = 8;
6958
        lineSize = width * 4;
6959
        break;
6960
      default:
6961
        throw new Error('invalid format');
6962
    }
6963
6964
    // prefix every row with predictor 0
6965
    var literals = new Uint8Array((1 + lineSize) * height);
6966
    var offsetLiterals = 0, offsetBytes = 0;
6967
    var y, i;
6968
    for (y = 0; y < height; ++y) {
6969
      literals[offsetLiterals++] = 0; // no prediction
6970
      literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize),
6971
                   offsetLiterals);
6972
      offsetBytes += lineSize;
6973
      offsetLiterals += lineSize;
6974
    }
6975
6976
    if (kind === ImageKind.GRAYSCALE_1BPP) {
6977
      // inverting for B/W
6978
      offsetLiterals = 0;
6979
      for (y = 0; y < height; y++) {
6980
        offsetLiterals++; // skipping predictor
6981
        for (i = 0; i < lineSize; i++) {
6982
          literals[offsetLiterals++] ^= 0xFF;
6983
        }
6984
      }
6985
    }
6986
6987
    var ihdr = new Uint8Array([
6988
      width >> 24 & 0xff,
6989
      width >> 16 & 0xff,
6990
      width >> 8 & 0xff,
6991
      width & 0xff,
6992
      height >> 24 & 0xff,
6993
      height >> 16 & 0xff,
6994
      height >> 8 & 0xff,
6995
      height & 0xff,
6996
      bitDepth, // bit depth
6997
      colorType, // color type
6998
      0x00, // compression method
6999
      0x00, // filter method
7000
      0x00 // interlace method
7001
    ]);
7002
7003
    var len = literals.length;
7004
    var maxBlockLength = 0xFFFF;
7005
7006
    var deflateBlocks = Math.ceil(len / maxBlockLength);
7007
    var idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4);
7008
    var pi = 0;
7009
    idat[pi++] = 0x78; // compression method and flags
7010
    idat[pi++] = 0x9c; // flags
7011
7012
    var pos = 0;
7013
    while (len > maxBlockLength) {
7014
      // writing non-final DEFLATE blocks type 0 and length of 65535
7015
      idat[pi++] = 0x00;
7016
      idat[pi++] = 0xff;
7017
      idat[pi++] = 0xff;
7018
      idat[pi++] = 0x00;
7019
      idat[pi++] = 0x00;
7020
      idat.set(literals.subarray(pos, pos + maxBlockLength), pi);
7021
      pi += maxBlockLength;
7022
      pos += maxBlockLength;
7023
      len -= maxBlockLength;
7024
    }
7025
7026
    // writing non-final DEFLATE blocks type 0
7027
    idat[pi++] = 0x01;
7028
    idat[pi++] = len & 0xff;
7029
    idat[pi++] = len >> 8 & 0xff;
7030
    idat[pi++] = (~len & 0xffff) & 0xff;
7031
    idat[pi++] = (~len & 0xffff) >> 8 & 0xff;
7032
    idat.set(literals.subarray(pos), pi);
7033
    pi += literals.length - pos;
7034
7035
    var adler = adler32(literals, 0, literals.length); // checksum
7036
    idat[pi++] = adler >> 24 & 0xff;
7037
    idat[pi++] = adler >> 16 & 0xff;
7038
    idat[pi++] = adler >> 8 & 0xff;
7039
    idat[pi++] = adler & 0xff;
0 ignored issues
show
Unused Code introduced by
The assignment to variable pi seems to be never used. Consider removing it.
Loading history...
7040
7041
    // PNG will consists: header, IHDR+data, IDAT+data, and IEND.
7042
    var pngLength = PNG_HEADER.length + (CHUNK_WRAPPER_SIZE * 3) +
7043
                    ihdr.length + idat.length;
7044
    var data = new Uint8Array(pngLength);
7045
    var offset = 0;
7046
    data.set(PNG_HEADER, offset);
7047
    offset += PNG_HEADER.length;
7048
    writePngChunk('IHDR', ihdr, data, offset);
7049
    offset += CHUNK_WRAPPER_SIZE + ihdr.length;
7050
    writePngChunk('IDATA', idat, data, offset);
7051
    offset += CHUNK_WRAPPER_SIZE + idat.length;
7052
    writePngChunk('IEND', new Uint8Array(0), data, offset);
7053
7054
    return PDFJS.createObjectURL(data, 'image/png');
7055
  }
7056
7057
  return function convertImgDataToPng(imgData) {
7058
    var kind = (imgData.kind === undefined ?
7059
                ImageKind.GRAYSCALE_1BPP : imgData.kind);
7060
    return encode(imgData, kind);
7061
  };
7062
})();
7063
7064
var SVGExtraState = (function SVGExtraStateClosure() {
7065
  function SVGExtraState() {
7066
    this.fontSizeScale = 1;
7067
    this.fontWeight = SVG_DEFAULTS.fontWeight;
7068
    this.fontSize = 0;
7069
7070
    this.textMatrix = IDENTITY_MATRIX;
7071
    this.fontMatrix = FONT_IDENTITY_MATRIX;
7072
    this.leading = 0;
7073
7074
    // Current point (in user coordinates)
7075
    this.x = 0;
7076
    this.y = 0;
7077
7078
    // Start of text line (in text coordinates)
7079
    this.lineX = 0;
7080
    this.lineY = 0;
7081
7082
    // Character and word spacing
7083
    this.charSpacing = 0;
7084
    this.wordSpacing = 0;
7085
    this.textHScale = 1;
7086
    this.textRise = 0;
7087
7088
    // Default foreground and background colors
7089
    this.fillColor = SVG_DEFAULTS.fillColor;
7090
    this.strokeColor = '#000000';
7091
7092
    this.fillAlpha = 1;
7093
    this.strokeAlpha = 1;
7094
    this.lineWidth = 1;
7095
    this.lineJoin = '';
7096
    this.lineCap = '';
7097
    this.miterLimit = 0;
7098
7099
    this.dashArray = [];
7100
    this.dashPhase = 0;
7101
7102
    this.dependencies = [];
7103
7104
    // Clipping
7105
    this.clipId = '';
7106
    this.pendingClip = false;
7107
7108
    this.maskId = '';
7109
  }
7110
7111
  SVGExtraState.prototype = {
7112
    clone: function SVGExtraState_clone() {
7113
      return Object.create(this);
7114
    },
7115
    setCurrentPoint: function SVGExtraState_setCurrentPoint(x, y) {
7116
      this.x = x;
7117
      this.y = y;
7118
    }
7119
  };
7120
  return SVGExtraState;
7121
})();
7122
7123
var SVGGraphics = (function SVGGraphicsClosure() {
7124
  function createScratchSVG(width, height) {
7125
    var NS = 'http://www.w3.org/2000/svg';
7126
    var svg = document.createElementNS(NS, 'svg:svg');
7127
    svg.setAttributeNS(null, 'version', '1.1');
7128
    svg.setAttributeNS(null, 'width', width + 'px');
7129
    svg.setAttributeNS(null, 'height', height + 'px');
7130
    svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);
7131
    return svg;
7132
  }
7133
7134
  function opListToTree(opList) {
7135
    var opTree = [];
7136
    var tmp = [];
7137
    var opListLen = opList.length;
7138
7139
    for (var x = 0; x < opListLen; x++) {
7140
      if (opList[x].fn === 'save') {
7141
        opTree.push({'fnId': 92, 'fn': 'group', 'items': []});
7142
        tmp.push(opTree);
7143
        opTree = opTree[opTree.length - 1].items;
7144
        continue;
7145
      }
7146
7147
      if(opList[x].fn === 'restore') {
7148
        opTree = tmp.pop();
7149
      } else {
7150
        opTree.push(opList[x]);
7151
      }
7152
    }
7153
    return opTree;
7154
  }
7155
7156
  /**
7157
   * Formats float number.
7158
   * @param value {number} number to format.
7159
   * @returns {string}
7160
   */
7161
  function pf(value) {
7162
    if (value === (value | 0)) { // integer number
7163
      return value.toString();
7164
    }
7165
    var s = value.toFixed(10);
7166
    var i = s.length - 1;
7167
    if (s[i] !== '0') {
7168
      return s;
7169
    }
7170
    // removing trailing zeros
7171
    do {
7172
      i--;
7173
    } while (s[i] === '0');
7174
    return s.substr(0, s[i] === '.' ? i : i + 1);
7175
  }
7176
7177
  /**
7178
   * Formats transform matrix. The standard rotation, scale and translate
7179
   * matrices are replaced by their shorter forms, and for identity matrix
7180
   * returns empty string to save the memory.
7181
   * @param m {Array} matrix to format.
7182
   * @returns {string}
7183
   */
7184
  function pm(m) {
7185
    if (m[4] === 0 && m[5] === 0) {
7186
      if (m[1] === 0 && m[2] === 0) {
7187
        if (m[0] === 1 && m[3] === 1) {
7188
          return '';
7189
        }
7190
        return 'scale(' + pf(m[0]) + ' ' + pf(m[3]) + ')';
7191
      }
7192
      if (m[0] === m[3] && m[1] === -m[2]) {
7193
        var a = Math.acos(m[0]) * 180 / Math.PI;
7194
        return 'rotate(' + pf(a) + ')';
7195
      }
7196
    } else {
7197
      if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1) {
7198
        return 'translate(' + pf(m[4]) + ' ' + pf(m[5]) + ')';
7199
      }
7200
    }
7201
    return 'matrix(' + pf(m[0]) + ' ' + pf(m[1]) + ' ' + pf(m[2]) + ' ' +
7202
      pf(m[3]) + ' ' + pf(m[4]) + ' ' + pf(m[5]) + ')';
7203
  }
7204
7205
  function SVGGraphics(commonObjs, objs) {
7206
    this.current = new SVGExtraState();
7207
    this.transformMatrix = IDENTITY_MATRIX; // Graphics state matrix
7208
    this.transformStack = [];
7209
    this.extraStack = [];
7210
    this.commonObjs = commonObjs;
7211
    this.objs = objs;
7212
    this.pendingEOFill = false;
7213
7214
    this.embedFonts = false;
7215
    this.embeddedFonts = {};
7216
    this.cssStyle = null;
7217
  }
7218
7219
  var NS = 'http://www.w3.org/2000/svg';
7220
  var XML_NS = 'http://www.w3.org/XML/1998/namespace';
7221
  var XLINK_NS = 'http://www.w3.org/1999/xlink';
7222
  var LINE_CAP_STYLES = ['butt', 'round', 'square'];
7223
  var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
7224
  var clipCount = 0;
7225
  var maskCount = 0;
7226
7227
  SVGGraphics.prototype = {
7228
    save: function SVGGraphics_save() {
7229
      this.transformStack.push(this.transformMatrix);
7230
      var old = this.current;
7231
      this.extraStack.push(old);
7232
      this.current = old.clone();
7233
    },
7234
7235
    restore: function SVGGraphics_restore() {
7236
      this.transformMatrix = this.transformStack.pop();
7237
      this.current = this.extraStack.pop();
7238
7239
      this.tgrp = document.createElementNS(NS, 'svg:g');
7240
      this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
7241
      this.pgrp.appendChild(this.tgrp);
7242
    },
7243
7244
    group: function SVGGraphics_group(items) {
7245
      this.save();
7246
      this.executeOpTree(items);
7247
      this.restore();
7248
    },
7249
7250
    loadDependencies: function SVGGraphics_loadDependencies(operatorList) {
7251
      var fnArray = operatorList.fnArray;
7252
      var fnArrayLen = fnArray.length;
7253
      var argsArray = operatorList.argsArray;
7254
7255
      var self = this;
7256
      for (var i = 0; i < fnArrayLen; i++) {
7257
        if (OPS.dependency === fnArray[i]) {
7258
          var deps = argsArray[i];
7259
          for (var n = 0, nn = deps.length; n < nn; n++) {
7260
            var obj = deps[n];
7261
            var common = obj.substring(0, 2) === 'g_';
7262
            var promise;
7263
            if (common) {
7264
              promise = new Promise(function(resolve) {
7265
                self.commonObjs.get(obj, resolve);
0 ignored issues
show
Bug introduced by
The variable obj is changed as part of the for loop for example by deps.n on line 7260. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
7266
              });
7267
            } else {
7268
              promise = new Promise(function(resolve) {
7269
                self.objs.get(obj, resolve);
0 ignored issues
show
Bug introduced by
The variable obj is changed as part of the for loop for example by deps.n on line 7260. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
7270
              });
7271
            }
7272
            this.current.dependencies.push(promise);
7273
          }
7274
        }
7275
      }
7276
      return Promise.all(this.current.dependencies);
7277
    },
7278
7279
    transform: function SVGGraphics_transform(a, b, c, d, e, f) {
7280
      var transformMatrix = [a, b, c, d, e, f];
7281
      this.transformMatrix = PDFJS.Util.transform(this.transformMatrix,
7282
                                                  transformMatrix);
7283
7284
      this.tgrp = document.createElementNS(NS, 'svg:g');
7285
      this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
7286
    },
7287
7288
    getSVG: function SVGGraphics_getSVG(operatorList, viewport) {
7289
      this.svg = createScratchSVG(viewport.width, viewport.height);
7290
      this.viewport = viewport;
7291
7292
      return this.loadDependencies(operatorList).then(function () {
7293
        this.transformMatrix = IDENTITY_MATRIX;
7294
        this.pgrp = document.createElementNS(NS, 'svg:g'); // Parent group
7295
        this.pgrp.setAttributeNS(null, 'transform', pm(viewport.transform));
7296
        this.tgrp = document.createElementNS(NS, 'svg:g'); // Transform group
7297
        this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
7298
        this.defs = document.createElementNS(NS, 'svg:defs');
7299
        this.pgrp.appendChild(this.defs);
7300
        this.pgrp.appendChild(this.tgrp);
7301
        this.svg.appendChild(this.pgrp);
7302
        var opTree = this.convertOpList(operatorList);
7303
        this.executeOpTree(opTree);
7304
        return this.svg;
7305
      }.bind(this));
7306
    },
7307
7308
    convertOpList: function SVGGraphics_convertOpList(operatorList) {
7309
      var argsArray = operatorList.argsArray;
7310
      var fnArray = operatorList.fnArray;
7311
      var fnArrayLen  = fnArray.length;
7312
      var REVOPS = [];
7313
      var opList = [];
7314
7315
      for (var op in OPS) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
7316
        REVOPS[OPS[op]] = op;
7317
      }
7318
7319
      for (var x = 0; x < fnArrayLen; x++) {
7320
        var fnId = fnArray[x];
7321
        opList.push({'fnId' : fnId, 'fn': REVOPS[fnId], 'args': argsArray[x]});
7322
      }
7323
      return opListToTree(opList);
7324
    },
7325
7326
    executeOpTree: function SVGGraphics_executeOpTree(opTree) {
7327
      var opTreeLen = opTree.length;
7328
      for(var x = 0; x < opTreeLen; x++) {
7329
        var fn = opTree[x].fn;
7330
        var fnId = opTree[x].fnId;
7331
        var args = opTree[x].args;
7332
7333
        switch (fnId | 0) {
7334
          case OPS.beginText:
0 ignored issues
show
Bug introduced by
The variable OPS seems to be never declared. If this is a global, consider adding a /** global: OPS */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
7335
            this.beginText();
7336
            break;
7337
          case OPS.setLeading:
7338
            this.setLeading(args);
7339
            break;
7340
          case OPS.setLeadingMoveText:
7341
            this.setLeadingMoveText(args[0], args[1]);
7342
            break;
7343
          case OPS.setFont:
7344
            this.setFont(args);
7345
            break;
7346
          case OPS.showText:
7347
            this.showText(args[0]);
7348
            break;
7349
          case OPS.showSpacedText:
7350
            this.showText(args[0]);
7351
            break;
7352
          case OPS.endText:
7353
            this.endText();
7354
            break;
7355
          case OPS.moveText:
7356
            this.moveText(args[0], args[1]);
7357
            break;
7358
          case OPS.setCharSpacing:
7359
            this.setCharSpacing(args[0]);
7360
            break;
7361
          case OPS.setWordSpacing:
7362
            this.setWordSpacing(args[0]);
7363
            break;
7364
          case OPS.setHScale:
7365
            this.setHScale(args[0]);
7366
            break;
7367
          case OPS.setTextMatrix:
7368
            this.setTextMatrix(args[0], args[1], args[2],
7369
                               args[3], args[4], args[5]);
7370
            break;
7371
          case OPS.setLineWidth:
7372
            this.setLineWidth(args[0]);
7373
            break;
7374
          case OPS.setLineJoin:
7375
            this.setLineJoin(args[0]);
7376
            break;
7377
          case OPS.setLineCap:
7378
            this.setLineCap(args[0]);
7379
            break;
7380
          case OPS.setMiterLimit:
7381
            this.setMiterLimit(args[0]);
7382
            break;
7383
          case OPS.setFillRGBColor:
7384
            this.setFillRGBColor(args[0], args[1], args[2]);
7385
            break;
7386
          case OPS.setStrokeRGBColor:
7387
            this.setStrokeRGBColor(args[0], args[1], args[2]);
7388
            break;
7389
          case OPS.setDash:
7390
            this.setDash(args[0], args[1]);
7391
            break;
7392
          case OPS.setGState:
7393
            this.setGState(args[0]);
7394
            break;
7395
          case OPS.fill:
7396
            this.fill();
7397
            break;
7398
          case OPS.eoFill:
7399
            this.eoFill();
7400
            break;
7401
          case OPS.stroke:
7402
            this.stroke();
7403
            break;
7404
          case OPS.fillStroke:
7405
            this.fillStroke();
7406
            break;
7407
          case OPS.eoFillStroke:
7408
            this.eoFillStroke();
7409
            break;
7410
          case OPS.clip:
7411
            this.clip('nonzero');
7412
            break;
7413
          case OPS.eoClip:
7414
            this.clip('evenodd');
7415
            break;
7416
          case OPS.paintSolidColorImageMask:
7417
            this.paintSolidColorImageMask();
7418
            break;
7419
          case OPS.paintJpegXObject:
7420
            this.paintJpegXObject(args[0], args[1], args[2]);
7421
            break;
7422
          case OPS.paintImageXObject:
7423
            this.paintImageXObject(args[0]);
7424
            break;
7425
          case OPS.paintInlineImageXObject:
7426
            this.paintInlineImageXObject(args[0]);
7427
            break;
7428
          case OPS.paintImageMaskXObject:
7429
            this.paintImageMaskXObject(args[0]);
7430
            break;
7431
          case OPS.paintFormXObjectBegin:
7432
            this.paintFormXObjectBegin(args[0], args[1]);
7433
            break;
7434
          case OPS.paintFormXObjectEnd:
7435
            this.paintFormXObjectEnd();
7436
            break;
7437
          case OPS.closePath:
7438
            this.closePath();
7439
            break;
7440
          case OPS.closeStroke:
7441
            this.closeStroke();
7442
            break;
7443
          case OPS.closeFillStroke:
7444
            this.closeFillStroke();
7445
            break;
7446
          case OPS.nextLine:
7447
            this.nextLine();
7448
            break;
7449
          case OPS.transform:
7450
            this.transform(args[0], args[1], args[2], args[3],
7451
                           args[4], args[5]);
7452
            break;
7453
          case OPS.constructPath:
7454
            this.constructPath(args[0], args[1]);
7455
            break;
7456
          case OPS.endPath:
7457
            this.endPath();
7458
            break;
7459
          case 92:
7460
            this.group(opTree[x].items);
7461
            break;
7462
          default:
7463
            warn('Unimplemented method '+ fn);
7464
            break;
7465
        }
7466
      }
7467
    },
7468
7469
    setWordSpacing: function SVGGraphics_setWordSpacing(wordSpacing) {
7470
      this.current.wordSpacing = wordSpacing;
7471
    },
7472
7473
    setCharSpacing: function SVGGraphics_setCharSpacing(charSpacing) {
7474
      this.current.charSpacing = charSpacing;
7475
    },
7476
7477
    nextLine: function SVGGraphics_nextLine() {
7478
      this.moveText(0, this.current.leading);
7479
    },
7480
7481
    setTextMatrix: function SVGGraphics_setTextMatrix(a, b, c, d, e, f) {
7482
      var current = this.current;
7483
      this.current.textMatrix = this.current.lineMatrix = [a, b, c, d, e, f];
7484
7485
      this.current.x = this.current.lineX = 0;
7486
      this.current.y = this.current.lineY = 0;
7487
7488
      current.xcoords = [];
7489
      current.tspan = document.createElementNS(NS, 'svg:tspan');
7490
      current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
7491
      current.tspan.setAttributeNS(null, 'font-size',
7492
                                   pf(current.fontSize) + 'px');
7493
      current.tspan.setAttributeNS(null, 'y', pf(-current.y));
7494
7495
      current.txtElement = document.createElementNS(NS, 'svg:text');
7496
      current.txtElement.appendChild(current.tspan);
7497
    },
7498
7499
    beginText: function SVGGraphics_beginText() {
7500
      this.current.x = this.current.lineX = 0;
7501
      this.current.y = this.current.lineY = 0;
7502
      this.current.textMatrix = IDENTITY_MATRIX;
7503
      this.current.lineMatrix = IDENTITY_MATRIX;
7504
      this.current.tspan = document.createElementNS(NS, 'svg:tspan');
7505
      this.current.txtElement = document.createElementNS(NS, 'svg:text');
7506
      this.current.txtgrp = document.createElementNS(NS, 'svg:g');
7507
      this.current.xcoords = [];
7508
    },
7509
7510
    moveText: function SVGGraphics_moveText(x, y) {
7511
      var current = this.current;
7512
      this.current.x = this.current.lineX += x;
7513
      this.current.y = this.current.lineY += y;
7514
7515
      current.xcoords = [];
7516
      current.tspan = document.createElementNS(NS, 'svg:tspan');
7517
      current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
7518
      current.tspan.setAttributeNS(null, 'font-size',
7519
                                   pf(current.fontSize) + 'px');
7520
      current.tspan.setAttributeNS(null, 'y', pf(-current.y));
7521
    },
7522
7523
    showText: function SVGGraphics_showText(glyphs) {
7524
      var current = this.current;
7525
      var font = current.font;
7526
      var fontSize = current.fontSize;
7527
7528
      if (fontSize === 0) {
7529
        return;
7530
      }
7531
7532
      var charSpacing = current.charSpacing;
7533
      var wordSpacing = current.wordSpacing;
7534
      var fontDirection = current.fontDirection;
7535
      var textHScale = current.textHScale * fontDirection;
7536
      var glyphsLength = glyphs.length;
7537
      var vertical = font.vertical;
7538
      var widthAdvanceScale = fontSize * current.fontMatrix[0];
7539
7540
      var x = 0, i;
7541
      for (i = 0; i < glyphsLength; ++i) {
7542
        var glyph = glyphs[i];
7543
        if (glyph === null) {
7544
          // word break
7545
          x += fontDirection * wordSpacing;
7546
          continue;
7547
        } else if (isNum(glyph)) {
7548
          x += -glyph * fontSize * 0.001;
7549
          continue;
7550
        }
7551
        current.xcoords.push(current.x + x * textHScale);
7552
7553
        var width = glyph.width;
7554
        var character = glyph.fontChar;
7555
        var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;
7556
        x += charWidth;
7557
7558
        current.tspan.textContent += character;
7559
      }
7560
      if (vertical) {
7561
        current.y -= x * textHScale;
7562
      } else {
7563
        current.x += x * textHScale;
7564
      }
7565
7566
      current.tspan.setAttributeNS(null, 'x',
7567
                                   current.xcoords.map(pf).join(' '));
7568
      current.tspan.setAttributeNS(null, 'y', pf(-current.y));
7569
      current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
7570
      current.tspan.setAttributeNS(null, 'font-size',
7571
                                   pf(current.fontSize) + 'px');
7572
      if (current.fontStyle !== SVG_DEFAULTS.fontStyle) {
7573
        current.tspan.setAttributeNS(null, 'font-style', current.fontStyle);
7574
      }
7575
      if (current.fontWeight !== SVG_DEFAULTS.fontWeight) {
7576
        current.tspan.setAttributeNS(null, 'font-weight', current.fontWeight);
7577
      }
7578
      if (current.fillColor !== SVG_DEFAULTS.fillColor) {
7579
        current.tspan.setAttributeNS(null, 'fill', current.fillColor);
7580
      }
7581
7582
      current.txtElement.setAttributeNS(null, 'transform',
7583
                                        pm(current.textMatrix) +
7584
                                        ' scale(1, -1)' );
7585
      current.txtElement.setAttributeNS(XML_NS, 'xml:space', 'preserve');
7586
      current.txtElement.appendChild(current.tspan);
7587
      current.txtgrp.appendChild(current.txtElement);
7588
7589
      this.tgrp.appendChild(current.txtElement);
7590
7591
    },
7592
7593
    setLeadingMoveText: function SVGGraphics_setLeadingMoveText(x, y) {
7594
      this.setLeading(-y);
7595
      this.moveText(x, y);
7596
    },
7597
7598
    addFontStyle: function SVGGraphics_addFontStyle(fontObj) {
7599
      if (!this.cssStyle) {
7600
        this.cssStyle = document.createElementNS(NS, 'svg:style');
7601
        this.cssStyle.setAttributeNS(null, 'type', 'text/css');
7602
        this.defs.appendChild(this.cssStyle);
7603
      }
7604
7605
      var url = PDFJS.createObjectURL(fontObj.data, fontObj.mimetype);
7606
      this.cssStyle.textContent +=
7607
        '@font-face { font-family: "' + fontObj.loadedName + '";' +
7608
        ' src: url(' + url + '); }\n';
7609
    },
7610
7611
    setFont: function SVGGraphics_setFont(details) {
7612
      var current = this.current;
7613
      var fontObj = this.commonObjs.get(details[0]);
7614
      var size = details[1];
7615
      this.current.font = fontObj;
7616
7617
      if (this.embedFonts && fontObj.data &&
7618
          !this.embeddedFonts[fontObj.loadedName]) {
7619
        this.addFontStyle(fontObj);
7620
        this.embeddedFonts[fontObj.loadedName] = fontObj;
7621
      }
7622
7623
      current.fontMatrix = (fontObj.fontMatrix ?
7624
                            fontObj.fontMatrix : FONT_IDENTITY_MATRIX);
7625
7626
      var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
7627
                                 (fontObj.bold ? 'bold' : 'normal');
7628
      var italic = fontObj.italic ? 'italic' : 'normal';
7629
7630
      if (size < 0) {
7631
        size = -size;
7632
        current.fontDirection = -1;
7633
      } else {
7634
        current.fontDirection = 1;
7635
      }
7636
      current.fontSize = size;
7637
      current.fontFamily = fontObj.loadedName;
7638
      current.fontWeight = bold;
7639
      current.fontStyle = italic;
7640
7641
      current.tspan = document.createElementNS(NS, 'svg:tspan');
7642
      current.tspan.setAttributeNS(null, 'y', pf(-current.y));
7643
      current.xcoords = [];
7644
    },
7645
7646
    endText: function SVGGraphics_endText() {
7647
      if (this.current.pendingClip) {
7648
        this.cgrp.appendChild(this.tgrp);
7649
        this.pgrp.appendChild(this.cgrp);
7650
      } else {
7651
        this.pgrp.appendChild(this.tgrp);
7652
      }
7653
      this.tgrp = document.createElementNS(NS, 'svg:g');
7654
      this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
7655
    },
7656
7657
    // Path properties
7658
    setLineWidth: function SVGGraphics_setLineWidth(width) {
7659
      this.current.lineWidth = width;
7660
    },
7661
    setLineCap: function SVGGraphics_setLineCap(style) {
7662
      this.current.lineCap = LINE_CAP_STYLES[style];
7663
    },
7664
    setLineJoin: function SVGGraphics_setLineJoin(style) {
7665
      this.current.lineJoin = LINE_JOIN_STYLES[style];
7666
    },
7667
    setMiterLimit: function SVGGraphics_setMiterLimit(limit) {
7668
      this.current.miterLimit = limit;
7669
    },
7670
    setStrokeRGBColor: function SVGGraphics_setStrokeRGBColor(r, g, b) {
7671
      var color = Util.makeCssRgb(r, g, b);
7672
      this.current.strokeColor = color;
7673
    },
7674
    setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) {
7675
      var color = Util.makeCssRgb(r, g, b);
7676
      this.current.fillColor = color;
7677
      this.current.tspan = document.createElementNS(NS, 'svg:tspan');
7678
      this.current.xcoords = [];
7679
    },
7680
    setDash: function SVGGraphics_setDash(dashArray, dashPhase) {
7681
      this.current.dashArray = dashArray;
7682
      this.current.dashPhase = dashPhase;
7683
    },
7684
7685 View Code Duplication
    constructPath: function SVGGraphics_constructPath(ops, args) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
7686
      var current = this.current;
7687
      var x = current.x, y = current.y;
7688
      current.path = document.createElementNS(NS, 'svg:path');
7689
      var d = [];
7690
      var opLength = ops.length;
7691
7692
      for (var i = 0, j = 0; i < opLength; i++) {
7693
        switch (ops[i] | 0) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
7694
          case OPS.rectangle:
0 ignored issues
show
Bug introduced by
The variable OPS seems to be never declared. If this is a global, consider adding a /** global: OPS */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
7695
            x = args[j++];
7696
            y = args[j++];
7697
            var width = args[j++];
7698
            var height = args[j++];
7699
            var xw = x + width;
7700
            var yh = y + height;
7701
            d.push('M', pf(x), pf(y), 'L', pf(xw) , pf(y), 'L', pf(xw), pf(yh),
7702
                   'L', pf(x), pf(yh), 'Z');
7703
            break;
7704
          case OPS.moveTo:
7705
            x = args[j++];
7706
            y = args[j++];
7707
            d.push('M', pf(x), pf(y));
7708
            break;
7709
          case OPS.lineTo:
7710
            x = args[j++];
7711
            y = args[j++];
7712
            d.push('L', pf(x) , pf(y));
7713
            break;
7714
          case OPS.curveTo:
7715
            x = args[j + 4];
7716
            y = args[j + 5];
7717
            d.push('C', pf(args[j]), pf(args[j + 1]), pf(args[j + 2]),
7718
                   pf(args[j + 3]), pf(x), pf(y));
7719
            j += 6;
7720
            break;
7721
          case OPS.curveTo2:
7722
            x = args[j + 2];
7723
            y = args[j + 3];
7724
            d.push('C', pf(x), pf(y), pf(args[j]), pf(args[j + 1]),
7725
                   pf(args[j + 2]), pf(args[j + 3]));
7726
            j += 4;
7727
            break;
7728
          case OPS.curveTo3:
7729
            x = args[j + 2];
7730
            y = args[j + 3];
7731
            d.push('C', pf(args[j]), pf(args[j + 1]), pf(x), pf(y),
7732
                   pf(x), pf(y));
7733
            j += 4;
7734
            break;
7735
          case OPS.closePath:
7736
            d.push('Z');
7737
            break;
7738
        }
7739
      }
7740
      current.path.setAttributeNS(null, 'd', d.join(' '));
7741
      current.path.setAttributeNS(null, 'stroke-miterlimit',
7742
                                  pf(current.miterLimit));
7743
      current.path.setAttributeNS(null, 'stroke-linecap', current.lineCap);
7744
      current.path.setAttributeNS(null, 'stroke-linejoin', current.lineJoin);
7745
      current.path.setAttributeNS(null, 'stroke-width',
7746
                                  pf(current.lineWidth) + 'px');
7747
      current.path.setAttributeNS(null, 'stroke-dasharray',
7748
                                  current.dashArray.map(pf).join(' '));
7749
      current.path.setAttributeNS(null, 'stroke-dashoffset',
7750
                                  pf(current.dashPhase) + 'px');
7751
      current.path.setAttributeNS(null, 'fill', 'none');
7752
7753
      this.tgrp.appendChild(current.path);
7754
      if (current.pendingClip) {
7755
        this.cgrp.appendChild(this.tgrp);
7756
        this.pgrp.appendChild(this.cgrp);
7757
      } else {
7758
        this.pgrp.appendChild(this.tgrp);
7759
      }
7760
      // Saving a reference in current.element so that it can be addressed
7761
      // in 'fill' and 'stroke'
7762
      current.element = current.path;
7763
      current.setCurrentPoint(x, y);
7764
    },
7765
7766
    endPath: function SVGGraphics_endPath() {
7767
      var current = this.current;
7768
      if (current.pendingClip) {
7769
        this.cgrp.appendChild(this.tgrp);
7770
        this.pgrp.appendChild(this.cgrp);
7771
      } else {
7772
        this.pgrp.appendChild(this.tgrp);
7773
      }
7774
      this.tgrp = document.createElementNS(NS, 'svg:g');
7775
      this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
7776
    },
7777
7778
    clip: function SVGGraphics_clip(type) {
7779
      var current = this.current;
7780
      // Add current path to clipping path
7781
      current.clipId = 'clippath' + clipCount;
7782
      clipCount++;
7783
      this.clippath = document.createElementNS(NS, 'svg:clipPath');
7784
      this.clippath.setAttributeNS(null, 'id', current.clipId);
7785
      var clipElement = current.element.cloneNode();
7786
      if (type === 'evenodd') {
7787
        clipElement.setAttributeNS(null, 'clip-rule', 'evenodd');
7788
      } else {
7789
        clipElement.setAttributeNS(null, 'clip-rule', 'nonzero');
7790
      }
7791
      this.clippath.setAttributeNS(null, 'transform', pm(this.transformMatrix));
7792
      this.clippath.appendChild(clipElement);
7793
      this.defs.appendChild(this.clippath);
7794
7795
      // Create a new group with that attribute
7796
      current.pendingClip = true;
7797
      this.cgrp = document.createElementNS(NS, 'svg:g');
7798
      this.cgrp.setAttributeNS(null, 'clip-path',
7799
                               'url(#' + current.clipId + ')');
7800
      this.pgrp.appendChild(this.cgrp);
7801
    },
7802
7803
    closePath: function SVGGraphics_closePath() {
7804
      var current = this.current;
7805
      var d = current.path.getAttributeNS(null, 'd');
7806
      d += 'Z';
7807
      current.path.setAttributeNS(null, 'd', d);
7808
    },
7809
7810
    setLeading: function SVGGraphics_setLeading(leading) {
7811
      this.current.leading = -leading;
7812
    },
7813
7814
    setTextRise: function SVGGraphics_setTextRise(textRise) {
7815
      this.current.textRise = textRise;
7816
    },
7817
7818
    setHScale: function SVGGraphics_setHScale(scale) {
7819
      this.current.textHScale = scale / 100;
7820
    },
7821
7822
    setGState: function SVGGraphics_setGState(states) {
7823
      for (var i = 0, ii = states.length; i < ii; i++) {
7824
        var state = states[i];
7825
        var key = state[0];
7826
        var value = state[1];
7827
7828
        switch (key) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
7829
          case 'LW':
7830
            this.setLineWidth(value);
7831
            break;
7832
          case 'LC':
7833
            this.setLineCap(value);
7834
            break;
7835
          case 'LJ':
7836
            this.setLineJoin(value);
7837
            break;
7838
          case 'ML':
7839
            this.setMiterLimit(value);
7840
            break;
7841
          case 'D':
7842
            this.setDash(value[0], value[1]);
7843
            break;
7844
          case 'RI':
7845
            break;
7846
          case 'FL':
7847
            break;
7848
          case 'Font':
7849
            this.setFont(value);
7850
            break;
7851
          case 'CA':
7852
            break;
7853
          case 'ca':
7854
            break;
7855
          case 'BM':
7856
            break;
7857
          case 'SMask':
7858
            break;
7859
        }
7860
      }
7861
    },
7862
7863
    fill: function SVGGraphics_fill() {
7864
      var current = this.current;
7865
      current.element.setAttributeNS(null, 'fill', current.fillColor);
7866
    },
7867
7868
    stroke: function SVGGraphics_stroke() {
7869
      var current = this.current;
7870
      current.element.setAttributeNS(null, 'stroke', current.strokeColor);
7871
      current.element.setAttributeNS(null, 'fill', 'none');
7872
    },
7873
7874
    eoFill: function SVGGraphics_eoFill() {
7875
      var current = this.current;
7876
      current.element.setAttributeNS(null, 'fill', current.fillColor);
7877
      current.element.setAttributeNS(null, 'fill-rule', 'evenodd');
7878
    },
7879
7880
    fillStroke: function SVGGraphics_fillStroke() {
7881
      // Order is important since stroke wants fill to be none.
7882
      // First stroke, then if fill needed, it will be overwritten.
7883
      this.stroke();
7884
      this.fill();
7885
    },
7886
7887
    eoFillStroke: function SVGGraphics_eoFillStroke() {
7888
      this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd');
7889
      this.fillStroke();
7890
    },
7891
7892
    closeStroke: function SVGGraphics_closeStroke() {
7893
      this.closePath();
7894
      this.stroke();
7895
    },
7896
7897
    closeFillStroke: function SVGGraphics_closeFillStroke() {
7898
      this.closePath();
7899
      this.fillStroke();
7900
    },
7901
7902
    paintSolidColorImageMask:
7903
        function SVGGraphics_paintSolidColorImageMask() {
7904
      var current = this.current;
7905
      var rect = document.createElementNS(NS, 'svg:rect');
7906
      rect.setAttributeNS(null, 'x', '0');
7907
      rect.setAttributeNS(null, 'y', '0');
7908
      rect.setAttributeNS(null, 'width', '1px');
7909
      rect.setAttributeNS(null, 'height', '1px');
7910
      rect.setAttributeNS(null, 'fill', current.fillColor);
7911
      this.tgrp.appendChild(rect);
7912
    },
7913
7914
    paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) {
7915
      var current = this.current;
7916
      var imgObj = this.objs.get(objId);
7917
      var imgEl = document.createElementNS(NS, 'svg:image');
7918
      imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src);
7919
      imgEl.setAttributeNS(null, 'width', imgObj.width + 'px');
7920
      imgEl.setAttributeNS(null, 'height', imgObj.height + 'px');
7921
      imgEl.setAttributeNS(null, 'x', '0');
7922
      imgEl.setAttributeNS(null, 'y', pf(-h));
7923
      imgEl.setAttributeNS(null, 'transform',
7924
                           'scale(' + pf(1 / w) + ' ' + pf(-1 / h) + ')');
7925
7926
      this.tgrp.appendChild(imgEl);
7927
      if (current.pendingClip) {
7928
        this.cgrp.appendChild(this.tgrp);
7929
        this.pgrp.appendChild(this.cgrp);
7930
      } else {
7931
        this.pgrp.appendChild(this.tgrp);
7932
      }
7933
    },
7934
7935
    paintImageXObject: function SVGGraphics_paintImageXObject(objId) {
7936
      var imgData = this.objs.get(objId);
7937
      if (!imgData) {
7938
        warn('Dependent image isn\'t ready yet');
7939
        return;
7940
      }
7941
      this.paintInlineImageXObject(imgData);
7942
    },
7943
7944
    paintInlineImageXObject:
7945
        function SVGGraphics_paintInlineImageXObject(imgData, mask) {
7946
      var current = this.current;
7947
      var width = imgData.width;
7948
      var height = imgData.height;
7949
7950
      var imgSrc = convertImgDataToPng(imgData);
7951
      var cliprect = document.createElementNS(NS, 'svg:rect');
7952
      cliprect.setAttributeNS(null, 'x', '0');
7953
      cliprect.setAttributeNS(null, 'y', '0');
7954
      cliprect.setAttributeNS(null, 'width', pf(width));
7955
      cliprect.setAttributeNS(null, 'height', pf(height));
7956
      current.element = cliprect;
7957
      this.clip('nonzero');
7958
      var imgEl = document.createElementNS(NS, 'svg:image');
7959
      imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc);
7960
      imgEl.setAttributeNS(null, 'x', '0');
7961
      imgEl.setAttributeNS(null, 'y', pf(-height));
7962
      imgEl.setAttributeNS(null, 'width', pf(width) + 'px');
7963
      imgEl.setAttributeNS(null, 'height', pf(height) + 'px');
7964
      imgEl.setAttributeNS(null, 'transform',
7965
                           'scale(' + pf(1 / width) + ' ' +
7966
                           pf(-1 / height) + ')');
7967
      if (mask) {
7968
        mask.appendChild(imgEl);
7969
      } else {
7970
        this.tgrp.appendChild(imgEl);
7971
      }
7972
      if (current.pendingClip) {
7973
        this.cgrp.appendChild(this.tgrp);
7974
        this.pgrp.appendChild(this.cgrp);
7975
      } else {
7976
        this.pgrp.appendChild(this.tgrp);
7977
      }
7978
    },
7979
7980
    paintImageMaskXObject:
7981
        function SVGGraphics_paintImageMaskXObject(imgData) {
7982
      var current = this.current;
7983
      var width = imgData.width;
7984
      var height = imgData.height;
7985
      var fillColor = current.fillColor;
7986
7987
      current.maskId = 'mask' + maskCount++;
7988
      var mask = document.createElementNS(NS, 'svg:mask');
7989
      mask.setAttributeNS(null, 'id', current.maskId);
7990
7991
      var rect = document.createElementNS(NS, 'svg:rect');
7992
      rect.setAttributeNS(null, 'x', '0');
7993
      rect.setAttributeNS(null, 'y', '0');
7994
      rect.setAttributeNS(null, 'width', pf(width));
7995
      rect.setAttributeNS(null, 'height', pf(height));
7996
      rect.setAttributeNS(null, 'fill', fillColor);
7997
      rect.setAttributeNS(null, 'mask', 'url(#' + current.maskId +')');
7998
      this.defs.appendChild(mask);
7999
      this.tgrp.appendChild(rect);
8000
8001
      this.paintInlineImageXObject(imgData, mask);
8002
    },
8003
8004
    paintFormXObjectBegin:
8005
        function SVGGraphics_paintFormXObjectBegin(matrix, bbox) {
8006
      this.save();
8007
8008
      if (isArray(matrix) && matrix.length === 6) {
8009
        this.transform(matrix[0], matrix[1], matrix[2],
8010
                       matrix[3], matrix[4], matrix[5]);
8011
      }
8012
8013
      if (isArray(bbox) && bbox.length === 4) {
8014
        var width = bbox[2] - bbox[0];
8015
        var height = bbox[3] - bbox[1];
8016
8017
        var cliprect = document.createElementNS(NS, 'svg:rect');
8018
        cliprect.setAttributeNS(null, 'x', bbox[0]);
8019
        cliprect.setAttributeNS(null, 'y', bbox[1]);
8020
        cliprect.setAttributeNS(null, 'width', pf(width));
8021
        cliprect.setAttributeNS(null, 'height', pf(height));
8022
        this.current.element = cliprect;
8023
        this.clip('nonzero');
8024
        this.endPath();
8025
      }
8026
    },
8027
8028
    paintFormXObjectEnd:
8029
        function SVGGraphics_paintFormXObjectEnd() {
8030
      this.restore();
8031
    }
8032
  };
8033
  return SVGGraphics;
8034
})();
8035
8036
PDFJS.SVGGraphics = SVGGraphics;
8037
//#endif
8038
8039
8040
}).call((typeof window === 'undefined') ? this : window);
8041
8042
if (!PDFJS.workerSrc && typeof document !== 'undefined') {
8043
  // workerSrc is not set -- using last script url to define default location
8044
  PDFJS.workerSrc = (function () {
8045
    'use strict';
8046
    var scriptTagContainer = document.body ||
8047
                             document.getElementsByTagName('head')[0];
8048
    var pdfjsSrc = scriptTagContainer.lastChild.src;
8049
    return pdfjsSrc && pdfjsSrc.replace(/\.js$/i, '.worker.js');
8050
  })();
8051
}
8052
8053